使用通用方法扩展多个模型的关联

Extending association of multiple models with common method

我希望能够使用通用代码从不同模型扩展多个关联,例如从 extending_relation_method class 方法。但是我无法在这个方法中实现 self 成为关系对象。有什么建议么?谢谢。

module ModelMixin
  extend ActiveSupport::Concern

  module ClassMethods
    def extending_relation_method
      owner = proxy_association.owner
      # some processing
      self
    end
  end
end

class Model < ActiveRecord::Base
  include ModelMixin

  def self.test1
    self
  end

  has_many :field_values, as: :owner, autosave: true do
    # works
    define_method :test1 do
      self
    end

    # works
    def test2
      self
    end

    # do not work
    define_method :test3, &(Model.method(:extending_relation_method).unbind.bind(self))
    define_method :test4, &(Model.method(:extending_relation_method).unbind.bind(Model))
  end
end

更新:

现在我认为问题可以简化为找出此行为的原因和解决方法:

proc1 = Proc.new { self }

def method_for_proc(*args)
  self
end
proc2 = method(:method_for_proc).to_proc

1.instance_exec(&proc1)
#=> 1
# as expected

1.instance_exec(&proc2)
#=> main
# why??

通过将共享方法替换为共享过程解决了原始问题,但我想了解为什么会这样。

module ModelMixin
  EXTENDING_RELATION_PROC = Proc.new do
    owner = proxy_association.owner
    # some processing
    self
  end
end

class Model < ActiveRecord::Base

  has_many :field_values, as: :owner, autosave: true do
    # works
    define_method :test, &EXTENDING_RELATION_PROC
  end
end

要调查您的 procs 问题,您可以在 to_proc 方法的源代码中查看注释 http://ruby-doc.org/core-2.2.0/Method.html#method-i-to_proc。所以 to_proc 不是通过方法主体创建新的 Proc,而是通过调用此方法(在这种情况下绑定到 main)。

但我认为在您的具体情况下,最好这样写:

module ModuleMixin
  def extending_relation_method
    # some processing
    self
  end
end

class Model < ActiveRecord::Base
  has_many :field_values, as: :owner, autosave: true do
    include ModuleMixin
  end
end