前提
サンプルコード等、Ruby on Railsを前提にしてます
概要
inverse_of、class_nameの説明をします。
どちらもActiveRecordの関連付けに用いるオプションです。
inverse_ofとは
Rails に双方向関連を明示し、同一オブジェクトを共有したり、バリデーションを適切に行うための設定です。
class_nameとは
関連名と実際のクラス名を明示的に指定するためのオプションです。
普段は暗黙的にRailsが判断してくれています。
どんな時に使うか
まず、Rails でモデルの関連を素直に設定すると、よくこうなります。
class User < ApplicationRecord
has_one :user_profile, dependent: :destroy
end
class UserProfile < ApplicationRecord
belongs_to :user
end
# bad
user.user_profile.nickname
user.user_profile というのが、なんとも言えず読みにくい。
そのコードを
# good
user.profile.nickname
こういう自然と読めるコードを書きたいときに、
- 「関連名とクラス名を対応させる」 → class_name
- 「反対側の関連がどれかを伝える」 → inverse_of
をセットで使うと便利です。
設定方法
公式のソース
サンプルコード
先ほどのUserの例の延長で書きます。
class User < ApplicationRecord
has_one :profile,
dependent: :destroy,
class_name: 'UserProfile', # ← 関連名とクラス名が異なるので、明示的に指定する
inverse_of: :user # ← UserProfile 側の :user と対応
end
class UserProfile < ApplicationRecord
belongs_to :user,
inverse_of: :profile # ← User 側の :profile と対応
end
これによって、先ほどもあげた
# good!
user.profile.nickname
のような、シンプルで自然なコードを記述することができます。
また、Rails的にも双方向関連を扱えるようになります。
他の例
個人的にやってみた例を挙げます。
変更前
# 部署と従業員で1対多の関係
class Department < ApplicationRecord
has_many :employees, dependent: :destroy,
end
class Employee < ApplicationRecord
belongs_to :department
end
# 参照の仕方
department.employees
これでもいいんですが、個人的には
- 全ての従業員が含まれうる命名 → employees
- 特定の所属に属する従業員の命名 → ?
この二つの違いがパッと見てわかるようにしたかったというのがあり、別名をつけました。
変更後
# 部署と従業員で1対多の関係
class Department < ApplicationRecord
has_many :members, # ← ここを変更
dependent: :destroy,
class_name: 'Employee',
inverse_of: :department
end
class Employee < ApplicationRecord
belongs_to :department,
inverse_of: :members
end
# 特定の所属のメンバー
department.members
departmentから見た時のみ、「employee」ではなく「member」と呼ぶことにしています。
そうすることで
- 全ての従業員が含まれうる命名 → employees
- 特定の所属に属する従業員の命名 → ?
この区別をつけやすくしました。
まとめ
チーム内で毎週2種類(This Week In Rails と Railsguides)の輪読会をしていて、双方向関連付について最近ガイドを読んだので、業務の中でいろいろと試してみています。
has_oneの関連テーブルなどで使える場面は多いのでよければ試してみて欲しいです。
参考