2

我当前的代码:

class Product < ActiveRecord::Base
  belongs_to :category
end

class Category < ActiveRecord::Base
  def method_missing name
    true
  end
end

Category.new.ex_undefined_method          #=> true
Product.last.category.ex_undefined_method #=> NoMethodError: undefined method `ex_undefined_method' for #<ActiveRecord::Associations::BelongsToAssociation:0xc4cd52c>

发生这种情况是因为 rails 中的代码仅将存在的方法传递给模型。

private
def method_missing(method, *args)
  if load_target
    if @target.respond_to?(method)
      if block_given?
        @target.send(method, *args)  { |*block_args| yield(*block_args) }
      else
        @target.send(method, *args)
      end
    else
      super
    end
  end
end

这就是我要的:

Product.last.category.ex_undefined_method #=> true

我怎样才能做到这一点?

4

3 回答 3

8

请注意,该AssociationProxy对象仅发送目标声称的方法respond_to?。因此,这里的修复也是更新respond_to?

class Category < ActiveRecord::Base
  def method_missing(name, *args, &block)
    if name =~ /^handleable/
      "Handled"
    else
      super
    end
  end

  def respond_to?(name)
    if name =~ /^handleable/
      true
    else
      super
    end
  end
end

事实上,如果你重新定义,你应该总是更新——你已经改变了你的类的接口,所以你需要确保每个人都知道它。见这里respond_to?method_missing

于 2011-06-01T08:55:32.807 回答
2

乔利特的回应确实是恕我直言的方式。

但是,如果您使用的是 Rails 3*,请确保包含在 responds_to? 中引入的第二个参数?定义:

def respond_to?(name,include_private = false)
  if name =~ /^handleable/
    true
  else
    super 
  end
end
于 2011-09-22T13:13:19.177 回答
0

代替

if @target.respond_to?(method)
  if block_given?
    @target.send(method, *args)  { |*block_args| yield(*block_args) }
  else
    @target.send(method, *args)
  end
else
  super
end

经过

if block_given?
  @target.send(method, *args)  { |*block_args| yield(*block_args) }
else
  @target.send(method, *args)
end

作为 AssociationProxy 的猴子补丁

于 2011-06-01T08:52:44.397 回答