使い方
特別に良い例ではないかもしれないが、次のような scaffold によるモデルを説明の前提とする。
$ rails g scaffold User name profile_id:integer $ rails g scaffold Photo title profile_id:integer $ rails g scaffold Profile message
User
と Photo
がそれぞれ Profile
モデルへの belongs_to
関連付けを持っている。このとき、通常であれば through: :profile
を指定した has_one
関連付けにより、User
と Photo
は関連付けられるが、foreign_key
及び primary_key
を指定することでパフォーマンスの良い関連付けが行える。
class User < ApplicationRecord belongs_to :profile # A) profiles テーブルを介して Photo モデルと関連付け has_one :photo, through: :profile # B) profiles テーブルを介さずに直接 Photo モデルと関連付け has_one :photo, foreign_key: :profile_id, primary_key: :profile_id end class Photo < ApplicationRecord belongs_to :profile # A) profiles テーブルを介して User モデルと関連付け has_one :user, through: :profile # B) profiles テーブルを介さずに直接 User モデルと関連付け has_one :user, foreign_key: :profile_id, primary_key: :profile_id end class Profile < ApplicationRecord has_one :user has_one :photo end
foreign_key
:自テーブルの外部キーを指定する。
primary_key
:リレーショナル先テーブルで主キーの代わりに用いるキーを指定する。
ベンチマーク
直接関連付けを行うと JOIN
が発生しないのでクエリ処理が高速になる。(クエリ2,000回による比較)
user system total real A) Through 1.123257 0.039119 1.162376 ( 1.164644) B) Direct 0.799194 0.038497 0.837691 ( 0.839629)
参考:
:primary_key と :foreign_key を同時指定して、主キーではないけど共通なカラム同士で関連付けする – Qiita
主キーが id 以外のテーブルを外部キーに設定する方法 | きまぐれ備忘録 (shara3.blogspot.com)
rails でモデル名のカラムに id 以外で参照する方法 – teratail
has_one has_many の primary_key と foreign_key – Qiita
Rails has_many relationship without using id – Stack Overflow