将模型上的所有方法调用委托给关联

时间:2012-03-28 19:31:47

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord

我正在使用具有多态关联的ActiveRecord模型,如下所示:

class Reach < ActiveRecord::Base
  belongs_to :reachable, :polymorphic => true
end

此模型就像一个代理。我需要做的是将该对象上的所有方法调用转发到关联的对象:reachable。我认为delegate在这里没有帮助,因为我必须明确命名我需要委派的所有方法。我需要delegate :all之类的东西来委托所有方法(不是all方法)。

3 个答案:

答案 0 :(得分:17)

你可以在这里做两件事:

  1. 较慢(性能方面)但更简单的方法是使用method_missing:

    class Reach < ActiveRecord::Base
    
      def method_missing(method, *args)
        return reachable.send(method, *args) if reachable.respond_to?(method)
        super
      end
    end
    
  2. 执行速度更快的方法是动态定义要委派的每个方法:

    class Reach < ActiveRecord::Base
    
      [:all, :my, :methods, :here].each do |m|
        define_method(m) do |*args|
          reachable.send(m, *args)
        end 
      end
    end
    
  3. 如果需要,您甚至可以以更动态的方式使用该方法,方法是使用Reach类,找到在其上单独定义的方法,并仅定义Reachable上的方法。我会手工做,因为有些你可能不想包括。

答案 1 :(得分:5)

对于Rails,我做了以下事情:

class User < ApplicationRecord
  has_one :member
  delegate (Member.new.attributes.keys - User.new.attributes.keys), to: :member
end

- User.new...不会覆盖User上的现有属性(例如created_at

但是,我不确定这种方法如何适用于多态性。

答案 2 :(得分:1)

我找到了一种使用细化来解决问题的简洁方法。标准库中已经有一个类允许将每个方法调用委托给目标对象。 Delegator and by extension SimpleDelegator 现在有一种方法可以将SimpleDelegator插入到继承链中,而无需使用优化直接从它继承:

def self.include_delegator
  mod = Module.new do
    include refine(SimpleDelegator) { yield if block_given? }
  end
  self.send :include, mod
end
include_delegator

现在为了利用SimpleDelegator在一个after initialize回调中设置委托目标,如下所示:

after_initialize do |instance|
  __setobj__(instance.reachable)
end

这相当于直接从SimpleDelegator继承并在构造中设置委托,没有手动管理委派的方法,你可以避免使用方法丢失。