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

时间:2012-02-15 15:58:21

标签: ruby-on-rails activerecord

我正试图绕过inverse_of并且我没有得到它。

生成的sql是什么样的,如果有的话?

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

很抱歉,如果这是一个基本问题。

我看到了这个例子:

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

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

8 个答案:

答案 0 :(得分:110)

the documentation开始,似乎: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对象,而不是默认情况下加载新对象。

答案 1 :(得分:37)

我认为:inverse_of在您使用尚未保留的关联时最有用。 E.g:

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参数,可以从内存中检索数据。

答案 2 :(得分:12)

从Rails 5.0的文档和伟大的。

Guide

双向关联

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

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

答案 3 :(得分:5)

只是每个人的更新 - 我们只使用了inverse_of我们的某个应用与has_many :through关联


它基本上使“原始”对象可用于“子”对象

所以,如果你使用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查询

答案 4 :(得分:4)

当我们有2个具有has_many和belongs_to关系的模型时,最好使用inverse_of来告知ActiveRecod它们属于关联的同一侧。因此,如果从一侧触发查询,如果从相反方向触发,它将从缓存缓存并提供服务。这提高了性能。从Rails 4.1开始,inverse_of将自动设置,如果我们使用foreign_key或我们需要明确设置的类名更改。

有关详细信息和示例的最佳文章。

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

答案 5 :(得分:3)

如果您在两个模型(用户和角色)之间存在has_many_through关系,并希望使用validates_presence of :user_id, :role_id针对不存在或无效的条目验证连接模型分配,则它非常有用。您仍然可以使用其关联@user.role(params[:role_id])生成User @user,以便保存用户不会导致Assignment模型的验证失败。

答案 6 :(得分:3)

答案 7 :(得分:-1)

请查看2两个有用的资源

请记住inverse_of的一些限制:

  

不适用于:通过关联。

     

不适用于:多态关联。

     对于belongs_to关联

,忽略has_many反向关联。