inverse_of做什么? 它产生了什么SQL?

我试图把我的头inverse_of ,我不明白。

什么生成的SQL看起来像,如果有的话?

如果与:has_many:belongs_to:has_many_and_belongs_to一起使用, inverse_of选项是否performance出相同的行为?

对不起,如果这是一个基本的问题。

我看到这个例子:

 class Player < ActiveRecord::Base has_many :cards, :inverse_of => :player end class Card < ActiveRecord::Base belongs_to :player, :inverse_of => :cards end 

从文档中 ,似乎是:inverse_of选项是一种避免SQL查询的方法,不会生成它们。 这是ActiveRecord使用已经加载的数据而不是通过关系重新获取的暗示。

他们的例子:

 class Dungeon < ActiveRecord::Base has_many :traps, :inverse_of => :dungeon has_one :evil_wizard, :inverse_of => :dungeon end class Trap < ActiveRecord::Base belongs_to :dungeon, :inverse_of => :traps end class EvilWizard < ActiveRecord::Base belongs_to :dungeon, :inverse_of => :evil_wizard end 

在这种情况下,调用dungeon.traps.first.dungeon应该返回原来的dungeon对象,而不是加载一个新的默认情况。

我认为:inverse_of当你使用尚未被保存的关联时, :inverse_of是最有用的。 例如:

 class Project < ActiveRecord::Base has_many :tasks, :inverse_of=>:project end class Task < ActiveRecord::Base belongs_to :project, :inverse_of=>:tasks end 

现在,在控制台中:

 irb> p = Project.new => #<Project id: nil, name: nil, ...> irb> t = p.tasks.build => #<Task id: nil, project_id: nil, ...> irb> t.project => #<Project id: nil, name: nil, ...> 

如果没有:inverse_of参数,t.project将会返回nil,因为它会触发一个sql查询并且数据还没有被存储。 使用:inverse_of参数,数据从内存中检索。

从Rails 5.0的文档和伟大的。

指南

双向关联

协会在两个方向上工作是正常的,需要在两个不同的模型上声明:

 class Author < ApplicationRecord has_many :books end class Book < ApplicationRecord belongs_to :author end 

默认情况下,Active Record不知道这些关联之间的连接。 这可能导致对象的两个副本不同步:

 a = Author.first b = a.books.first a.first_name == b.author.first_name # => true a.first_name = 'Manny' a.first_name == b.author.first_name # => false 

发生这种情况是因为a和b.author是同一个数据的两个不同的内存中表示,并且没有一个会自动从另一个的更改中刷新。 Active Record提供:inverse_of选项,以便您可以将这些关系通知给它:

 class Author < ApplicationRecord has_many :books, inverse_of: :author end class Book < ApplicationRecord belongs_to :author, inverse_of: :books end 

通过这些更改,Active Record将只加载作者对象的一个​​副本,从而防止出现不一致并提高应用程序的效率:

 a = Author.first b = a.books.first a.first_name == b.author.first_name # => true a.first_name = 'Manny' a.first_name == b.author.first_name # => true 

inverse_of支持有一些限制:

他们不通过协会工作。 它们不适用于:多态关联。 他们不作为协会工作。

对于belongs_to关联,has_many反向关联被忽略。 每个关联都将尝试自动查找逆关联并启发式地设置inverse_of选项(根据关联名称)。 大多数与标准名称的关联将被支持。 但是,包含以下选项的关联不会自动设置其逆向:

  • :条件
  • :通过
  • 多态
  • :foreign_key

只是每个人的更新 – 我们只是has_many :through关联在我们的应用程序中使用了inverse_of


它基本上使“起源”对象可用于“子”对象

所以如果你使用Rails的例子:

 class Dungeon < ActiveRecord::Base has_many :traps, :inverse_of => :dungeon has_one :evil_wizard, :inverse_of => :dungeon end class Trap < ActiveRecord::Base belongs_to :dungeon, :inverse_of => :traps validates :id, :presence => { :message => "Dungeon ID Required", :unless => :draft? } private def draft? self.dungeon.draft end end class EvilWizard < ActiveRecord::Base belongs_to :dungeon, :inverse_of => :evil_wizard end 

使用:inverse_of将允许您访问与之相反的数据对象,而不执行任何其他SQL查询

当我们有has_many和belongs_to关系的2个模型时,最好使用inverse_of来通知ActiveRecod它们属于关联的同一侧。 所以如果一个查询从一个方面被触发,它将caching,并从caching服务,如果从相反的方向触发。 这在性能上有所提高。 从Rails 4.1开始,inverse_of会自动设置,如果我们使用foreign_key或者更改类名,我们需要明确设置。

最好的文章的细节和例子。

http://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations

如果在两个模型User和Role之间有has_many_through关系,并且要validation连接模型Assignment与validates_presence of :user_id, :role_id非现有条目或无效条目,那么这很有用。 您仍然可以使用其关联@user.role(params[:role_id])生成一个User @user.role(params[:role_id])用户,以便保存用户不会导致对Assignment模型的validation失败。

请看看两个有用的资源

记住inverse_of一些限制:

不适用于:通过关联。

不适用于:多态关联。

对于belongs_to关联has_many反向关联被忽略。