はじめに
こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。
Rails の関連(has_many / belongs_to / has_one など)には inverse_of というオプションがあります。
これは「逆方向の関連が何であるか」を Rails に伝えるものです。
Rails は通常、関連を自動で推測してくれるのですが、複雑な関連やスコープ付き関連では推測できない場合があるので、明示的に書く必要が出てきます。
なぜ必要なのか?
例: has_many と belongs_to
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :writer, class_name: "Author", foreign_key: "author_id"
end
inverse_of を書いていないと、関連オブジェクトを呼ぶたびに新しいインスタンスが生成されることがあり、
「同じはずの author が別物」になってしまうケースが出ます。
これは特に メモリ上でのオブジェクト同一性を大事にする処理(キャッシュやバリデーション) で不具合の原因になります。
author = Author.new(name: "Taro")
book = author.books.build(title: "My Book")
book.writer.equal?(author) # => false の場合がある!
書き方のポイント
自動推測されない場合は必ず書く
- スコープ付き関連
-
class_name/foreign_keyを指定した関連 - 名前が変わっている関連
class User < ApplicationRecord
has_many :authored_articles,
class_name: "Article",
foreign_key: :author_id,
inverse_of: :author
end
class Article < ApplicationRecord
belongs_to :author,
class_name: "User",
inverse_of: :authored_articles
end
has_many :through の場合は効かない
through を経由した関連には inverse_of は使えません。
polymorphic 関連でも効かない
belongs_to :commentable, polymorphic: true のような関連では逆方向が特定できないため使えません。
まとめ
-
inverse_ofは関連の逆方向を Rails に教えるオプション - 通常は自動推測されるので書かなくて良いが、以下の場合は書くようにする
- スコープ付き関連
-
class_name/foreign_keyをカスタムした関連
-
throughやpolymorphic関連には使えない
参考資料