🐰

【Dynamoid で STI】複数のクラスを一つのテーブルにまとめる

2024/02/06に公開

Ruby on Rails で DynamoDB を ActiveRecord のように扱える Dynamoid を使用しています。
Users テーブルに以下のようなアイテムが入っていたとき、Rails 側で Users クラスとして取り扱うのが少し複雑になりそうだったので、なんとかならないかと思い調べました。

pk sk 説明
U_#id item_#item_id1 ユーザー保持アイテム
U_#id item_#item_id2 ユーザー保持アイテム
U_#id skill_#skill_id1 ユーザースキル
U_#id skill_#skill_id2 ユーザースキル
U_#id weakpoint 弱点

要約

  • STI(単一テーブル継承)を使う
  • model に type field を追加する

STI(単一テーブル継承)を使う

STI とは Single Table Inheritance の略で単一テーブル継承の略だそうです。

https://ja.wikipedia.org/wiki/単一テーブル継承

https://railsguides.jp/association_basics.html#単一テーブル継承-(sti)

もともとは、一つのテーブルから複数種類のクラスを扱うために ActiveRecord で用意されていた仕組みですが、Dynamoid でも同じ仕組みが用意されています。

model に type field を追加する

使い方は単純に model に type フィールドを追加するだけです。

class User
  include Dynamoid::Document

  table name: :user, key: :pk, read_capacity: 5, write_capacity: 5
  range :sk, :string
  field :type # <- これをついかする

end

class UserItem < User
  field :item_id, :string
  field :item_name, :string
end

class UserSkill < User
  field :skill_id, :string
  field :skill_name, :string
  field :damage_alg, :string
end

inheritance_field: で競合を回避

既に type field がテーブルに存在している場合などで type field を使用したくない場合は、inheritance_field: で回避することができます。

class User
  include Dynamoid::Document

  table name: :user, key: :pk, inheritance_field: :sti_type 
  range :sk, :string
  field :sti_type, :string
end

class UserItem < User
  field :item_id, :string
  field :item_name, :string
end

class UserSkill < User
  field :skill_id, :string
  field :skill_name, :string
  field :damage_alg, :string
end

最後に

ドキュメントを見ればすぐにわかることですが、STI からのつながりを理解するためにまとめました。
DynamoDB では今回の例のように、一つのテーブルでいろいろなタイプのアイテムを格納することが多いので、STI を用いるのが効果的でよく使うことになりそうです。

参考

https://ja.wikipedia.org/wiki/単一テーブル継承
https://railsguides.jp/association_basics.html#単一テーブル継承-(sti)
https://github.com/Dynamoid/dynamoid

Discussion