从 Rails 5 开始,何时需要手动设置 :inverse_of?

Posted

技术标签:

【中文标题】从 Rails 5 开始,何时需要手动设置 :inverse_of?【英文标题】:As of Rails 5, when is :inverse_of necessary to set manually? 【发布时间】:2019-01-09 09:15:34 【问题描述】:

我在不同的地方读到它在某些情况下会自动推断,但我发现有关此功能的文档很难理解。任何人都可以阐明这些原则吗? Rails 什么时候能够推断,Rails 什么时候不能推断逆?

我想考虑

多态关联 单表继承(例如,BundleProductIndividualProduct 都继承自 Product 并使用 products 表) 常规 has_one/has_many/belongs_to 关联 有很多通过:关联

一些背景:我正在维护一个相当大的 9 年历史的 Rails 应用程序,其中包含很多很多表。我想要一些关于哪些模型需要添加inverse_of: 而不必更改系统中的每个模型的指导。

【问题讨论】:

请检查这里(也许你已经这样做了,无论如何..):guides.rubyonrails.org/…,确切地说:“通过在 has_many 关联声明中包含 :inverse_of option,Active Record 现在将识别双向协会:...”。还有guides.rubyonrails.org/…、guides.rubyonrails.org/…。或者你可以举个例子来缩小你的问题范围。 我在问题中添加了更多上下文,以便您了解我的困境。 【参考方案1】:

如果你不设置 :inverse_of 记录,关联会做它的 最好将自己与正确的逆相匹配。自动逆 检测仅适用于 has_many、has_one 和 belongs_to 协会。 -- Rails API docs - ActiveRecord::Associations::ClassMethods

如果您有“非标准”命名,您可能需要提供以下选项:

反向关联的自动猜测使用启发式 基于类的名称,因此它可能不适用于所有人 关联,尤其是具有非标准名称的关联。 -- Rails API docs - ActiveRecord::Associations::ClassMethods

例如:

class Pet < ApplicationRecord
  belongs_to :owner, class_name: 'User'
end

class User < ApplicationRecord
  has_many :pets
end

如果我们调用pet.owner,它可能会导致数据库命中,即使我们已经加载了该记录。

如果我们添加inverse_of 选项:

class Pet < ApplicationRecord
  belongs_to :owner, class_name: 'User', inverse_of: :pets
end

class User < ApplicationRecord
  has_many :pets, inverse_of: :owner
end

现在,如果我们已经在内存中拥有 owner 记录,那么 pet.owner 将指向相同的 owner

一般来说,显式设置inverse_of 并没有什么坏处,因此您可以针对每个不确定的情况进行设置。您还可以通过查看 accessing the assocation creates a DB query via the console 或在您的测试套件中使用 shoulda-matchers 来手动测试是否需要。

【讨论】:

【参考方案2】:

您可以在ActiveRecord::Reflection::AssociationReflection#automatic_inverse_of 中查找确切的推断过程。

Rails 尝试检测不具有 throughforeign_key 选项和范围且具有标准名称的 has_manyhas_onebelongs_to 的逆向(这也在 official guide 中进行了描述)。

【讨论】:

以上是关于从 Rails 5 开始,何时需要手动设置 :inverse_of?的主要内容,如果未能解决你的问题,请参考以下文章

使用(restful)rails 时事务何时开始

Rails 如何知道何时从 `sessions` 表中删除记录?

从 YML 文件设置 rails 重定向

502 Bad Gateway (too big header) on Elastic Beanstalk Nginx with Rails 5 App in Production

何时使用 Mongrel 作为 Rails 应用程序的 Web 服务器?

Rails 5 - 如何删除 twitter-bootstrap-rails gem 并手动安装