实施respond_to?使用active_record-acts_as gem的方法

时间:2015-01-16 18:00:49

标签: ruby-on-rails ruby activerecord

我正在使用active_record-acts_as gem在我的rails应用程序中实现多表继承。这个gem帮助子类像父类一样运行,因此它响应父类的方法。我想让父类也响应子类的方法,因为它简化了路由。

到目前为止,我有:

class ParentClass < ActiveRecord::Base
  actable as: :assetable

  def method_missing_with_specific(method, *args, &block)
    # specific is the associated child class instance
    if specific.respond_to?(method)
      specific.send(method, *args, &block)
    else
      method_missing_without_specific(method, *args, &block)
    end
  end

  alias_method_chain :method_missing, :specific

  def is_a_with_specific?(type)
    if assetable_type.constantize == type
      true
    else
      is_a_without_specific?(type)
    end
  end

  alias_method_chain :is_a?, :specific
end

这很有效,但我在实施respond_to?方法时无法使用method_missing方法。

我试过了:

def respond_to?(method, private=false)
  super || specific.respond_to?(method, private)
end

def respond_to_with_specific?(method, private=false)
  if specific.respond_to?(method, private)
    true
  else
    respond_to_without_specific?(method, private)
  end
end

alias_method_chain :respond_to?, :specific

这两种方法都导致我的测试失败:

 Failure/Error: Unable to find matching line from backtrace
 SystemStackError:
   stack level too deep
 # /Users/blueye/.rvm/gems/ruby-2.1.1/gems/activerecord-4.1.2/lib/active_record/transactions.rb:286
 # 
 #   Showing full backtrace because every line was filtered out.
 #   See docs for RSpec::Configuration#backtrace_exclusion_patterns and
 #   RSpec::Configuration#backtrace_inclusion_patterns for more information.

显然,我在与ActiveRecord交互时会产生某种无限递归,但我不确定如何。

在这种情况下如何实施respond_to?

更新

我在gem中找到了以下代码:

def respond_to?(name, include_private = false)
  super || acting_as.respond_to?(name)
end

这似乎会创建某种循环逻辑,其中每个类都将respond_to?委托给另一个。我尝试在子类中重写此方法,但调用super似乎只是委托gem模块中包含的方法。

1 个答案:

答案 0 :(得分:1)

您在respond_to?方法中调用respond_to_with_specific?,因此无限递归。

由于Child类应该具有Parents类 plus 的所有方法,所以你应该能够做到:

def respond_to_with_specific?(method, private=false)
  specific.respond_to_without_specific?(method, private)
end