has_manyとbelongs_toでinverse_ofオプションが必要なケースを検証してみました。
結論から書くとhas_many
でinverse_of
が必要なケースは検証できましたがbelongs_to
での必要なケースが不明でした。
has_manyでinverse_ofが必要なケース(ソース抜粋)
# app/models/blog.rb
has_many :articles, -> { order(id: :desc) }, dependent: :destroy, inverse_of: :blog
accepts_nested_attributes_for :articles, reject_if: :all_blank
#app/models/article.rb
validate ->(article) {
if article.blog.title == article.title
errors.add(:title, 'blogタイトルとarticleタイトルが同じではいけない')
end
}
has_manyでinverse_ofが不要なケース(ソース抜粋)
# app/models/blog.rb
has_many :articles, dependent: :destroy
accepts_nested_attributes_for :articles, reject_if: :all_blank
# app/models/article.rb
# 必要なケースと同じソース
上記の結果から分かること
-
-> { order(id: :desc) }
の有無でinverse_of
の必要性が決まりました。 -
-> { order(id: :desc) }
がある状態でinverse_of
をつけないとvalidate
の中のarticle.blog
が参照できずnilになりました。(inverse_ofをつけると参照できました)
belolngs_toにinverse_ofが必要なケースを検証
(そもそも= simple_form_for(@article)
のフォームから親のBlogを生成するケース自体、稀かもしれませんが…)
belongs_toでinverse_ofをつけた場合(ソース抜粋)
# app/models/blog.rb
validate ->(blog) {
if blog.articles.map(&:title).include?(blog.title)
errors.add(:title, 'blogタイトルとarticleタイトルが同じではいけない')
end
}
# app/models/article.rb
belongs_to :blog, inverse_of: :articles
accepts_nested_attributes_for :blog
フォームで送信したはずのArticleのデータblog.articles
が参照できませんでした。(デバッグのためblog.articles.length
と書いても0
が返ります)
belongs_to
にinverse_of
を書けば保存前のblog.articles
が参照できると考えていましたが、実際にはそのような動きにはなりませんでした。
追記(2019年4月6日)
勉強会でご一緒した方にhas_many - belongs_to
の関係でbelongs_to
に設定したinverse_of
は現状サポートされていないとの情報を共有いただきました。
情報共有いただきまして感謝いたします!
# NOTE - for now, we're only supporting inverse setting from belongs_to back onto
# has_one associations.