Help us understand the problem. What is going on with this article?

Railsにおけるデータベース関連付けの記述方法

More than 1 year has passed since last update.

リレーションシップとは

データベース同士の関連性を定義するものですね。私は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人の生徒が使用することはないでしょう。

models/student.rb
class Student < ActiveRecord::Base
  has_one :desc
end
models/desc.rb
class Desc < ActiveRecord::Base
  belongs_to :student
end

机になんのデータが入っているのかはさておいて、has_oneとbelong_toが紐づけのコードになります。お互いの関係は1対1のですが、has_oneとbelong_toと別々のコードを使用しています。これは参照先のidを持っているかどうかで使い分けます。

1対多のつながり

小学校は多くのところが担任制だと思います。Teach(先生)に対してStudents(生徒)がたくさんいる状態ですね。その関係性は1対多であるといえます。

models/teacher.rb
class Teacher < ActiveRecord::Base
  has_many :students
end
models/student.rb
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を紐づけさせると以下のようになります。

models/student.rb
class Student < ActiveRecord::Base
  has_many :affilicationLists
  has_many :clubs, through :affilicationLists
end
models/club.rb
class Club < ActiveRecord::Base
  has_many :affilicationLists
  has_many :students, through :affilicationLists
end
models/affilicationList.rb
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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away