As of Rails 5, :inverse_of 什么时候需要手动设置?

As of Rails 5, when is :inverse_of necessary to set manually?

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

我愿意考虑

一些上下文: 我正在维护一个相当大的 9 岁 Rails 应用程序,其中有很多很多 table。我想就哪些模型需要添加 inverse_of: 而不是必须更改系统中的每个模型提供一些指导。

具体的推导过程可以在ActiveRecord::Reflection::AssociationReflection#automatic_inverse_of中查找。

Rails 尝试检测没有​​ throughforeign_key 选项和范围的 has_manyhas_onebelongs_to 的逆并具有标准名称(这在 official guide 中也有描述)。

If you do not set the :inverse_of record, the association will do its best to match itself up with the correct inverse. Automatic inverse detection only works on has_many, has_one, and belongs_to associations.
-- Rails API docs - ActiveRecord::Associations::ClassMethods

在您有 "non-standard" 命名的情况下,您可能需要提供以下选项:

The automatic guessing of the inverse association uses a heuristic based on the name of the class, so it may not work for all associations, especially the ones with non-standard names. -- 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 or by using shoulda-matchers 与您的测试套件来手动测试是否需要它。