リレーションシップとは
データベース同士の関連性を定義するものですね。私はRuby独自の表現だと思っていましたが、データベース用語のようです。
ここではRailsにおけるリレーションシップの指定方法について簡単にまとめて行こうと思います。
関連付けの種類
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
上記6種類です。has_one :throughとhas_and_belongs_to_many以外を使用して確認していきたいと思います。
関連付けを学校に例える
小学校に関するアプリを開発するという想定で行きたいと思います。誰でも経験したであろう小学校という場所をモチーフとしてリレーションシップを確認したいと思います。
1対1のつながり
データ上の1つのものに対し、他のデータ上の中から必ず1つしか存在しえないものを表すときに1対1の繋がりがあるといえます。
小学校で例えるなら、生徒と机でしょうか?Student(生徒)とDesc(机)は紐づいており、必ず1対1の関係にあります。机を2つもっている生徒や、逆に1つの机を2人の生徒が使用することはないでしょう。
class Student < ActiveRecord::Base
has_one :desc
end
class Desc < ActiveRecord::Base
belongs_to :student
end
机になんのデータが入っているのかはさておいて、has_oneとbelong_toが紐づけのコードになります。お互いの関係は1対1のですが、has_oneとbelong_toと別々のコードを使用しています。これは参照先のidを持っているかどうかで使い分けます。
1対多のつながり
小学校は多くのところが担任制だと思います。Teach(先生)に対してStudents(生徒)がたくさんいる状態ですね。その関係性は1対多であるといえます。
class Teacher < ActiveRecord::Base
has_many :students
end
class Student < ActiveRecord::Base
belongs_to :teacher
end
belong_toは変わりませんが、has_manyというのが登場しました。こちらが対多を意味するコードになります。注意すべきはhas_manyで宣言する場合は複数形でないといけないところです。Studentクラスは単数形ですが、has_manyのあとはstudentsになっています。
多対多のつながり
小学生には部活動はありませんでした。その代わりにクラブ活動がありました。クラブ活動は週に1、2回だったので掛け持ちが可能でした。その関係は多対多であるといえます。Studenst(生徒)とClub(クラブ)を直接紐づけることも可能ですが、先生としてはどの生徒がどのクラブに所属しているか把握しておきたいところです。そこで、AffiliationList(所属表)も作っておくことにします。
AffilicationClubListを介してStudentとClubを紐づけさせると以下のようになります。
class Student < ActiveRecord::Base
has_many :affilicationLists
has_many :clubs, through :affilicationLists
end
class Club < ActiveRecord::Base
has_many :affilicationLists
has_many :students, through :affilicationLists
end
class AffilicationList < ActiveRecord::Base
belongs_to :student
belongs_to :club
end
ちょっと複雑になりました。ただ、使用しているコードは今までと同じなので、分けて考えていけば理解できるかと思います。
AffilicationListを中心に考えると、ClubとStudentの関連付けは1対多の関係です。変わってくるのはClubとStudentのコンマ以降のthroughの部分です。has_manyのあとにthroughオプションを指定すると、throughのあとのモデルを経由してアクセスできるようになります。
student基準で考えると、affilicationListを経由してclubにアクセスできるようになるということです。
まとめ
- 1対1 belongs_toとhas_one
- 1対多 1側はbelongs_to、多側はhas_many
- 多対多 第3のデータを中継して指定。中継地からはbelongs_to。中継地にhas_manyでつなぎ、お互いをhas_many :throughで指定。
あとがき
この手の資料を検索すると、ツイッターを例にとって説明しているものがほとんどでした。今回はもう少し現実的な視点でまとめていきたいと思い、小学校でありそうな事柄で例えてみたのですが多少強引だったでしょうか?
私自身まだ理解しきっていないところがあるため、間違いありましたら指摘していただけると助かります。
参考
RailsGuides Active Record の関連付け (アソシエーション):https://railsguides.jp/association_basics.html
Rails Webook:http://ruby-rails.hatenadiary.com/entry/20141204/1417688260