ブシトラの日記

エンジニア1年生の雑多記事

Railsガイド6.0読み直す ~5章 Active Record の関連付け~

railsguides.jp

 

書いていく。

 

関連付けを使う理由

モデルとモデルの間には関連付けを行なう必要がありますが、その理由を御存じでしょうか。それは、関連付けを行う事であなたのコードでの共通操作をよりシンプルで簡単にするからです。

 だよねー。

関連付けの種類

has_one :[子供のモデル] => 親から子供
belongs_to :[親のモデル] => 子供から親

主となる方が has_one で従となる方が belongs_to になる。

 

  • belongs_to
  • has_one
  • has_many
  • has_many :through
  • has_one :through
  • has_and_belongs_to_many

・belongs_to関連付けで指定するモデル名は必ず「単数形」

 

2-1 belongs_to

宣言を行ったモデルのすべてのインスタンスは、他方のモデルのインスタンスに「従属(belongs to)」します。

2-2 has_one

belongs_toとは若干異なります。has_one関連付けの場合は、その宣言が行われているモデルのインスタンスが、他方のモデルのインスタンスを「まるごと含んでいる」または「所有している」ことを示します

2-3 has_many

has_many関連付けが使われている場合、「反対側」のモデルでは多くの場合belongs_toが使われます。has_many関連付けが使われている場合、そのモデルのインスタンスは、反対側のモデルの「0個以上の」インスタンスを所有します。

2-4 has_many :through 

has_many :through関連付けは、他方のモデルと「多対多」のつながりを設定する場合によく使われます。この関連付けは、2つのモデルの間に「第3のモデル」(joinモデル)が介在する点が特徴です。

2-5 has_one :through 

has_one :through関連付けは、他方のモデルに対して「1対1」のつながりを設定します。この関連付けは、2つのモデルの間に「第3のモデル」(joinモデル)が介在する点が特徴です。それによって、相手モデルの1つのインスタンスとマッチします

2-6 has_and_belongs_to_many

has_and_belongs_to_many関連付けは、他方のモデルと「多対多」のつながりを作成しますが、through:を指定した場合と異なり、第3のモデル(joinモデル)が介在しません(訳注: 後述するように結合用のテーブルは必要です)。

↑あまり使ったことない

2-7 has_one or belongs_to

区別の決め手となるのは外部キー(foreign key)をどちらに置くかです(外部キーは、belongs_toを追加した方のモデルのテーブルに追加されます)。もちろんこれだけでは決められません。データの実際の意味についてもう少し考えてみる必要があります。has_oneというリレーションは、主語となるものが目的語となるものを「所有している」ということを表しています。そして、所有されている側(目的語)の方が、所有している側(主語)を指し示しているということも表しています。たとえば、「供給者がアカウントを持っている」とみなす方が、「アカウントが供給者を持っている」と考えるよりも自然です。つまり、この場合の正しい関係は以下のようになります。

class Supplier < ApplicationRecord
  has_one :account
end

class Account < ApplicationRecord
  belongs_to :supplier
end
2-8 has_many :throughとhas_and_belongs_to_manyのどちらを選ぶか

どちらを使うかについてですが、経験上、リレーションシップのモデルそれ自体を独立したエンティティとして扱いたい(両モデルの関係そのものについて処理を行いたい)のであれば、中間にjoinモデルを使うhas_many :throughリレーションシップを選ぶのが最もシンプルです。リレーションシップのモデルで何か特別なことをする必要がまったくないのであれば、joinモデルの不要なhas_and_belongs_to_manyリレーションシップを使うのがシンプルです(ただし、こちらの場合はjoinモデルが不要な代わりに、専用のjoinテーブルを別途データベースに作成しておく必要がありますので、お忘れなきよう)。

2-9 ポリモーフィック関連付け

ポリモーフィック関連付けは、関連付けのやや高度な応用です。ポリモーフィック関連付けを使うと、ある1つのモデルが他の複数のモデルに属していることを、1つの関連付けだけで表現できます。

qiita.com

2-10 自己結合

データモデルを設計していると、時に自分自身に関連付けられる必要のあるモデルに出会うことがあります。たとえば、1つのデータベースモデルに全従業員を格納しておきたいが、マネージャーと部下(subordinate)の関係も追えるようにしておきたい場合が考えられます。この状況は、自己結合関連付けを用いてモデル化できます。

class Employee < ApplicationRecord
  has_many :subordinates, class_name: "Employee",
                          foreign_key: "manager_id"

  belongs_to :manager, class_name: "Employee", optional: true
end

上のように宣言しておくと、@employee.subordinates@employee.managerが使えるようになります。

自己結合むずい。。

・もし、従業員にマネージャーがいたら、マネージャーを取得 → @employee.manager

・更に、マネージャーに部下がいたら、その部下も取れる

→ @employee.subordinates

 

わかりやすい

morizyun.github.io

 

qiita.com

3 ヒントと注意事項

・reload? で更新

1. belongs_to関連付けを使う場合は、外部キーを作成する必要があります。2. has_and_belongs_to_many関連付けを使う場合は、適切なjoinテーブルを作成する必要があります。

Active Recordでスコープや次のオプションを使った場合、双方向の関連付けは自動的に認識されません。

  • :through
  • :foreign_key

Active Recordは:inverse_ofオプションを提供していて、これを使うと双方向の関連付けを明示的に宣言できます。

class Author < ApplicationRecord
  has_many :books, inverse_of: 'writer'
end

class Book < ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end

has_manyの関連付けを宣言するときに:inverse_ofオプションも含めることで、Active Recordは双方向の関連付けを認識するようになります。

 

4 関連付けの詳細情報

4.1 belongs_to関連付けの詳細

belongs_to関連付けは、別のモデルとの間に1対1の関連付けを作成します。データベースの用語で説明すると、この関連付けが行われているクラスには外部キーがあるということです。外部キーが自分のクラスではなく相手のクラスにあるのであれば、belongs_toではなくhas_oneを使う必要があります。

4.1.2 belongs_toのオプション

belongs_to関連付けでは以下のオプションがサポートされています。

  • :autosave
  • :class_name
  • :counter_cache
  • :dependent
  • :foreign_key
  • :primary_key
  • :inverse_of
  • :polymorphic
  • :touch
  • :validate
  • :optional

https://railsguides.jp/association_basics.html#belongs-to%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91%E3%81%AE%E8%A9%B3%E7%B4%B0

 

めちゃくちゃある。。w

4.2 has_one 関連付けの詳細

has_one関連付けは他のモデルと1対1対応します。データベースの観点では、この関連付けでは相手のクラスが外部キーを持ちます。相手ではなく自分のクラスが外部キーを持っているのであれば、belongs_toを使うべきです。

 

has_one関連付けでは以下のオプションがサポートされます。

  • :as
  • :autosave
  • :class_name
  • :dependent
  • :foreign_key
  • :inverse_of
  • :primary_key
  • :source
  • :source_type
  • :through
  • :validate

これもまためちゃくちゃある。読むの疲れるレベル

 

4.3 has_many 関連付けの詳細

 

books
books<<(object, ...)
books.delete(object, ...)
books.destroy(object, ...)
books=(objects)
book_ids
book_ids=(ids)
books.clear
books.empty?
books.size
books.find(...)
books.where(...)
books.exists?(...)
books.build(attributes = {}, ...)
books.create(attributes = {})
books.create!(attributes = {})
books.reload

 

ほぼ知ってたな。

5 シングルテーブル継承(STI)

感想

また読みに帰ってくる。量が多い。オプションも多い