协会延伸在哪里

时间:2013-07-04 03:11:12

标签: ruby-on-rails rails-activerecord

我有一个关联扩展方法,如下所示:

class Bundle < ActiveRecord::Base
  has_many :items do
    def foo
    end
  end

我尝试使用延迟作业/ sidekiq delay()方法,如下所示:

b.items.delay.foo

但我不能。您会看到,在调用延迟时,关联会立即评估到一组记录。该数组没有关联扩展方法。

所以我尝试检查b.items.proxy_association.methods,令我惊讶的是,foo()也不存在。

我的foo()方法中有哪个对象?

3 个答案:

答案 0 :(得分:1)

延迟作业的延迟功能检查对象是否响应排队的方法并返回NoMethodError,因为没有为Items类定义该功能。扩展的工作方式是将模块添加到proxy_association的所有者类,在这种情况下,您将能够从Bundle::BundleItemsAssociationExtension.instance_methods访问该函数。因此,即使传递关联对象,延迟方法也无法访问foo方法。我建议将方法移动到Items类,然后在其上调用延迟作业。

答案 1 :(得分:1)

此处collection_association.rb

#has_many calls this eventually
def build
  wrap_block_extension
  ...
end

然后

#here model refers to you model
#block_extension is the block you write with in the has_many definition(def foo blah blah)
def wrap_block_extension
  ...
  model.parent.const_set(extension_module_name, Module.new(&block_extension))
  options[:extend].push("#{model.parent}::#{extension_module_name}".constantize)
end

def extension_module_name
    @extension_module_name ||= "#{model.to_s.demodulize}#{name.to_s.camelize}AssociationExtension"
end

我没有查看源代码,但我认为我们可以从这里得到一个有根据的猜测:b.items返回一个对象(我忘记了类名,一些代理或其他东西,对不起),当时方法丢失发生了,它会调查其他地方,包括options[:extend],因此在这种情况下,它会通过b.items.foo向我们提供我们想要的内容。

但是当你打电话给b.items.bar时,它找不到任何相对的东西,所以它首先会检查b.items的'返回值',它是一个数组,是否响应方法{{ 1}},如果还没有,它会调用#bar进行最后的尝试。

在您的情况下,Item#bar#delay识别的方法,因此它非常像Array,所以tmp1 = b.items.all; tmp2 = tmp1.delay; tmp2.foo肯定无处可寻。

答案 2 :(得分:1)

谢谢那些回答的人。他们不是100%正确,但不是到目前为止。所以我会留下赏金,以便你们分享。

BundleItemsAssociationExtension混合到ActiveRecord :: Relation对象中。所以当我打电话时:

bundle.items.scoped.methods # returns array containing my :foo

所以ActiveRecord :: Relation对象是包含我的扩展方法的对象。


作为旁注:事实证明我不能在Relation对象上使用Delayed Job,因为它包含一个无法序列化的匿名模块。所以最后我必须使用类方法来完成我想要实现的目标。