2012-02-15 42 views
109

我试图让我的脑袋周围inverse_of,我不明白。inverse_of做什么?它产生了什么SQL?

生成的SQL的外观如何?

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

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

我看到这个例子:

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

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

回答

98

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对象,而不是加载一个新的将是默认的情况。

+5

您是否理解文档中的注释:“for belongs_to associations has_many反向关联会被忽略。”然而,文档使用了这个确切的例子。我在这里错过了什么? – dynex 2012-02-16 03:41:25

+1

我不完全确定。 'inverse_of'并没有真正被使用过,所以它可能是一个没有很好定义的行为。在您指出该功能之后,我尝试过使用它,但它并没有真正为我做任何有用的事情。 – tadman 2012-02-16 04:05:11

+46

这对我来说非常奇怪,因为在我看来,默认情况下总是需要这种行为,并且只有在无法推断关联名称时才需要使用:inverse_of。此外,定义中的不一致性也很麻烦,但在少数情况下它帮助了我。任何原因,我不应该坚持到处? – Ibrahim 2012-07-06 00:08:52

3

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

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查询

30

我想: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将返回零,因为它触发一个SQL查询和数据还没有存储。使用:inverse_of参数,数据从内存中检索。

+0

我有一个accept_nested_attributes_for的问题。默认情况下,只有现有关联对象的嵌套属性显示(编辑操作)。 例如,如果您想要用3个关联对象创建一个对象,则应该在模型中使用Model.new(new action)和:inverse_of。 – 2014-10-22 11:11:27

+0

就Rails 4和更高版本中的行为达成一致,但它在v3中工作得很好(除了一些后来的变体,尽管旧的语法在v3.2.13中再次运行)。并注意在连接模型中,不能验证id的存在 - 只有模型对象。似乎你可以有一个没有id的关联,在第4版“逻辑”中。 – JosephK 2015-09-16 01:57:18

+0

确切地说..':inverse_of'为我解决了一个问题,当以相同的形式创建新的父和子实体时。 – 2016-09-28 06:30:00

4

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

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

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

7

从Rails的5.0和伟大的文档。

Guide

双向关联

这是正常的协会在两个方向上工作,需要申报的两种不同的型号:

class Author < ApplicationRecord 
    has_many :books 
end 

class Book < ApplicationRecord 
    belongs_to :author 
end 

默认情况下,活动记录没有按”了解这些关联之间的联系。这可导致失去同步的目的的两个副本:

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 

这是因为一个和b.author是两个相同数据的不同内存中表示,并且没有一个自动地从变化到刷新另一个。活动记录提供了:inverse_of选项,以便您可以通知其这些关系的:

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

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

有了这些变化,活动记录将只加载author对象的一个​​副本,防止矛盾,使您的应用更高效:

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
+0

我正在使用Rails 5,并且要么添加'inverse_of',要么'a.first_name == b.author.first_name'的结果始终是ture。 – 2016-12-15 12:17:35