Railsには、belongs_toというアソシエーションが用意されています。本記事では、Railsを利用する際に、アソシエーションとはどのように機能するのか、その中で、belongs_toはどのような場合に使えるのかについて解説します。
Railsのアソシエーションとは
Ruby on Rails(以下、Railsと記述します)では、2つのActive Recordモデル同士のつながり(関連付け)をアソシエーションと呼んでいます。各モデル間には関連付けを宣言する必要があります。
モデル間の関連付けを宣言することで、1つのコードから関連情報をたどることができます。Active Recordの関連付けを行うと、2つのモデルの間のつながりを明示的にRailsに対して宣言できます。
belongs_toとは
モデルに対し、belongs_toで関連付けを行なうと、相手となるモデルとの間に「1対1」のつながりが設定されます。belongs_toで関連付けを宣言したモデルの、すべてのインスタンスは、相手となるモデルのインスタンスに従属します。
Railsアプリケーションで著者(Author)と書籍(Book)の情報を扱う場合、必ず1人の著者につき1冊しか書籍情報がなければ、belongs_toで宣言します。
belongs_toを使って関連付けを行う方法
belongs_toは、自分のテーブルと相手となるテーブルの関係が1対1で、従属関係にある場合のモデルの関連付けに使います。
1対1で従属関係にあるとは、相手モデルのテーブルに外部キーとして、自分モデルのidカラムを参照している関係にある2つのテーブルを指します。
belongs_toの書き方
Railsのbelongs_toを使って、2つのモデルの関連付けを宣言する場合、以下の形式に従って、コードを記述します。
【記述形式】
belongs_to(関連モデル名 [, scope, オプション])
指定する関連モデル名は、相手モデルの名前の単数形になります。以下によく使われいるオプションを紹介するので、参考にしてみてください。。
オプション | 内容 |
---|---|
:class_name | 関連するモデルクラス名を指定する 関連モデル名と参照先のクラス名を分けたい場合に使う |
:foreign_key | 参照先のテーブルの外部キーのカラム名を指定する |
:primary_key | 参照元(自分)のテーブルの主キーのカラム名を指定する |
:optional | 「true」を指定すると参照先のテーブルのデータが存在しない場合でもエラーにならない |
関連名をカスタマイズする方法
Railsのbelongs_toは、カスタマイズせずに基本の構文のまま使用できますが、関連付けの動作をカスタマイズする必要のある場合もあります。Railsのbelongs_toのカスタマイズを行う際は、作成するときに渡すオプションとスコープブロックを使います。
belongs_to関連付けでは、先にご紹介したよく使われるオプションのほか、以下のオプションがサポートされています。
オプション | 内容 |
---|---|
:autosave | 「true」に設定すると、親オブジェクトが保存されるたびに、読み込まれているすべての関連付けメンバを保存し、destroyフラグが立っているメンバを破棄する |
:counter_cache | 従属しているオブジェクトの数の検索効率を向上させる |
:dependent | オブジェクトが削除されるときに、関連付けられたオブジェクトが直接データべースから削除される |
:inverse_of | 関連付けの逆関連付けとなるhas_many関連付けまたはhas_one関連付けの名前を指定する |
:polymorphic | ポリモーフィック関連付けを指定できる |
:touch | 関連付けられているオブジェクトが保存またはdestroyされるたびに、そのオブジェクトのupdated_atまたはupdated_onタイムスタンプが現在時刻に設定される |
:validate | 「true」に設定すると、関連付けられたオブジェクトが保存時に必ず検証される |
関連付けで指定するモデル名は必ず単数形にする
Railsのbelongs_toで宣言するモデルの関連付けは、1対1です。そのため、belongs_toで指定する相手モデル名は、必ず単数形で指定します。1対多の関連付けとなるhas_manyアソシエーションでは、相手モデル名は必ず複数形で指定します。
Railsのbelongs_to以外のアソシエーション
RailsのActive Recordでテーブル間の関連付け(アソシエーション)を行うメソッドには、belongs_toのほか、has_one、has_manyもあります。これらの違いと使い方について、簡単に説明します。
こんな場合 | 使えるアソシエーション |
---|---|
自分のモデルが相手となるモデルに従属している | belongs_to |
自分のモデルと相手となるモデルが1対1 | has_one |
自分のモデルと相手となるモデルが1対多 | has_many |
has_oneに寄る関連付け
Railsのhas_oneは、相手となるモデルとの間に1対1の関連付けを設定します。belongs_toと似ていますが、has_oneの場合は、その宣言が行われているモデルのインスタンスが、他方のモデルのインスタンスを「まるごと含んでいる」という点で異なります。
【記述形式】
has_one(関連モデル名 [, scope ,オプション])
オプションとしては、主に以下のものがよく使われています。
オプション | 内容 |
---|---|
:class_name | 関連するモデルクラス名を指定する 関連モデル名と参照先のクラス名を分けたい場合に使う |
:foreign_key | 参照先のテーブルの外部キーのカラム名を指定する |
:primary_key | 参照元(自分)のテーブルの主キーのカラム名を指定する |
has_manyによる関連付け
Railsのhas_many関連付け、他のテーブルとの間に「1対多」のつながりがあることを示します。
参照相手となるモデルでは、多くの場合belongs_toが使われます。has_manyで関連付けを宣言する場合、相手となるモデル名は「複数形」にする必要があります。
【記述形式】
has_many(関連モデル名 [, scope ,オプション])
オプションとしては、以下のものがよく使われています。
オプション | 内容 |
---|---|
:class_name | 関連するモデルクラス名を指定する 関連モデル名と参照先のクラス名を分けたい場合に使う |
:foreign_key | 参照先のテーブルの外部キーのカラム名を指定する |
:primary_key | 参照元(自分)のテーブルの主キーのカラム名を指定する |
has_many :throughによる関連付け
has_many :throughは、相手となるモデルと「多対多」のつながりを設定する場合に使われます。
A、B、Cのモデルがあり、AとBを直接関連付けることはできないものの、間にCを介すことで、AからCをたどり、CからBをたどって、結果的にAとBが紐づく場合に、has_many :throughで関連付けを宣言することができます。
各アソシエーションの記述例
Railsの各アソシエーションの記述形式の「関連モデル名」部分は、モデル間のが「1対1」か「1対多」かによって、モデル名を単数形・複数形いずれで記述するかの使い分けが必要です。
【記述例】authorモデルとの関連付けを宣言する場合
belongs_to :author
has_one :author
has_many :authors
has_many :publishers, through: :authors
Railsのアソシエーションを覚えておこう!
モデルの関連付けは、一種のマクロ的な呼び出しとして実装されます。アソシエーションによって、モデル間の関連付けを宣言的に追加することができます。
belongs_toによって、あるモデルが他のモデルに「従属している」と宣言すると、2つのモデルのインスタンス間で、「主キー」と「 外部キー」の参照情報を保持するように、Railsに指示が伝わります。ほかのアソシエーションもまとめて使い方を覚えておきましょう。