使い方

特別に良い例ではないかもしれないが、次のような scaffold によるモデルを説明の前提とする。

$ rails g scaffold User name profile_id:integer
$ rails g scaffold Photo title profile_id:integer
$ rails g scaffold Profile message

UserPhoto がそれぞれ Profile モデルへの belongs_to 関連付けを持っている。このとき、通常であれば through: :profile を指定した has_one 関連付けにより、UserPhoto は関連付けられるが、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

タグ:

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です