そもそもhas_manyとは?
対象を複数持っている場合に使用します。
構文
1 2 3 |
class 親モデル < ActiveRecord::Base has_many :関連する子モデル(複数形) end |
実装
複数モデルが返る。「ActiveRecord Reration」(子モデルの配列みたいな構造)になる。
1 |
親モデル.find(1).子モデル(複数) |
has_manyのオプションの概要
オプション | 説明 |
---|---|
class_name | 1モデルに対して2つ以上のアソシエーションを組む場合に使用する。sourceとほぼ機能は同じだが中間テーブルがない場合はこちらを使う。ただ、そもそもモデル名とプログラムで使用しているインスタンス名が異なり、プログラム上での可読性が下がるのであまり使うことはない。 |
source | 「class_name」とほぼ機能は同じ。throughを使うような中間テーブルがある際にはこちらを使う。ただ、そもそもモデル名とプログラムで使用しているインスタンス名が異なり、プログラム上での可読性が下がるのであまり使うことはない。 |
foreign_key | 参照先(別テーブル)の外部キーのカラム名を指定する。 |
primary_key | 参照元(自分)のテーブルの外部キーのカラム名 |
through | 中間テーブルが複数ある場合に使用する。どの中間テーブルを使用すれば良いか経路を決めることができる。sourceと一緒に使用することが多い。 |
as | |
polymorphic | ポリモーフィック関連が使える。 |
dependent | 削除時のオプションです。親モデルを削除する際に子モデルがどのように削除されるかを決めることが可能です。 |
inverse_of | 一つの親モデルに複数の子モデルが関連づけられるオプションです。 |
詳細
source
「class_name」とほぼ機能は同じ。throughを使うような中間テーブルがある際にはこちらを使う。関連先テーブル名とアソシエーション名が同じ場合はsourceオプションは省略することが可能。異なる場合は「source: :モデル名」というように関連先テーブル名を記述しなければならない。ただ、そもそもモデル名とプログラムで使用しているインスタンス名が異なり、プログラム上での可読性が下がるのであまり使うことはない。
inverse_of
has_manyと一緒に使用するオプションです。
Articleモデル(1)とCommentsモデル(多)を別々の変数に代入したとしても、Comments(多)の方から1の方を参照することができるような設定です。同じインスタンスを同一メモリ上に格納するためのようです。
1 2 3 4 5 6 7 8 |
project = Project.first catepro = project.category_projects.first irb(main):034:0> project.title == catepro.project.title => true irb(main):035:0> project.title = "henko" => "henko" irb(main):036:0> project.title == catepro.project.title => true ←「親側の変数」に変更を加えたのに「子の変数」から辿って参照ができる。 |
なお、この機能を利用するためにはRails4.0までは明示的に指定する必要があったのですが、Rails4.1以降からはデフォルトで使用できるようになったようです。
dependentオプション
削除時のオプションになります。親モデルを削除する際に子モデルがどのように削除されるか決定することが可能です。
オプション名 | 説明 |
---|---|
destroy | 親レコードと一緒に子レコードを削除する。子レコードのコールバックも実行する。 |
delete_all | 親レコードと一緒に子レコードを削除する。SQL直接実行で直接DBから削除するのでコールバックなし。 |
nullify | 子レコードの外部キーをNULL更新する。 |
restrict_with_exception | 子レコードがある場合は「ActiveRecord::DeleteRestrictionError」が発生する。 |
restrict_with_error | 子レコードがある場合は削除が失敗し、親レコードにエラー情報を付与する。 |
中間テーブルを使った実装(多:多)
両端のテーブル
1 2 3 4 |
class モデル名 < ActiveRecord::Base has_many :関連名, through: :中間テーブル名 has_many :中間テーブル名 #throuthオプションを使用する際のおまじない end |
中間テーブル
1 2 3 4 |
class 中間テーブル名 < ActiveRecord::Base belongs_to :端テーブルA belongs_to :端テーブルB end |
実装
端モデルAに所属する端モデルBの一覧を中間テーブルから取得して、端モデルBに紐づく一覧のレコードを一括で取得するという処理を下記の文で記述できます。
1 |
端モデルA.find(1).端モデルB |
内部的に生成されるSQL
1 2 3 4 |
SELECT * FROM `端テーブルA` INNER JOIN `中間テーブル` ON `端テーブルA`.`主キー` = `中間テーブル`.`端テーブルAへの外部キー` WHERE `中間テーブル`.`端テーブルBへの外部キー` = 1 |
この記事へのコメントはありません。