首页 > 解决方案 > 为什么我在“has_many”关系中对“所有者”的调用不起作用?

问题描述

我正在使用 Rails 5.0.7.1,我在文档中看到我的 CollectionProxy 实例应该有权访问“@owner”实例变量:

Active Record 中的关联代理是持有关联的对象(称为@owner)和实际关联的对象(称为@target)之间的中间人。@reflection 中提供了任何代理所涉及的关联类型。这是 ActiveRecord::Reflection::AssociationReflection 类的一个实例。

blog.posts 中的关联代理将 blog 中的对象作为@owner,将其帖子的集合作为@target,@reflection 对象表示一个 :has_many 宏。

此类通过 method_missing 将未知方法委托给 @target。

在我的 Rails 应用程序中,我有以下(相当不切实际的)测试代码:

class Post < ApplicationRecord
  has_many :comments  do
    def number_five
      if owner.is_a? Post
        Comment.where(id: 5, post_id: self.id)
      end
    end
  end
end

class Comment < ApplicationRecord
  belongs_to :post
end

当我打电话时Post.last.commments.number_five,我收到以下错误:

NameError (undefined local variable or method `owner' for #
<Comment::ActiveRecord_Associations_CollectionProxy:0x00007fcbb9106120>)

当我添加byebug到 and 之间的行def number_fiveowner.is_a? Post检查 的值时self,我看到它是ActiveRecord::Associations::CollectionProxy,所以我认为owner在应该定义它的范围内调用。

我试过了Post.last.comments.instance_variables,我没有看到:@owner,只有以下内容:

[:@association, :@klass, :@table, :@values, :@offsets, 
:@loaded, :@predicate_builder, :@scope]

我还尝试了以下方法:

comments = Post.last.comments
def comments.get_owner
  self.owner
end

这返回与NameError上面相同。

对于它的价值,当我跑步时Post.last.comments.class,我看到了它Comment::ActiveRecord_Associations_CollectionProxy

鉴于文档的阅读方式,我希望能够从内部调用Post.last.comments.owner@owner从内部调用Post.last.comments(我都尝试过),并让它返回Post.last. 我的期望是错误的,还是我的代码错误,或者完全是别的什么?

标签: ruby-on-railsactiverecordrails-activerecord

解决方案


文档有点混乱。我记得当我第一次需要从扩展方法中脱离关联时,我不得不花几个小时猜测、阅读 Rails 源代码并尝试弄清楚这一点。

owner是您所追求的,但这是关联的一种方法,您可以通过以下方式获得关联proxy_association(这只是 的访问器方法@association):

has_many :comments  do
  def number_five
    if proxy_association.owner.is_a? Post
      #...
    end
  end
end

我不确定这是否是“正确”或“官方”的方式,但这是我自 Rails 4 以来一直在做的事情。


推荐阅读