我正在构建一个Rails 3 gem,它基本上修改了从ActiveRecord查询返回的记录。我正在做的一件事是重写method_missing
和respond_to?
方法,但似乎我的respond_to?
定义导致了一个无限循环,导致“SystemStackError:堆栈层太深”错误。Object.respond_to?卡在无限循环
这是我原来的这些方法的定义:
def respond_to?(name, *args)
super(name, *args) || parent_association.respond_to?(name)
end
def method_missing(name, *args, &block)
if parent_association.respond_to?(name)
parent_association.send(name, *args, &block)
else
super(name, *args, &block)
end
end
def parent_association
send(parent_association_name) # Essentially yields another ActiveRecord
# instance (e.g.: instance of User), but
# never returns itself.
end
在试图了解为什么这个无限循环正在发生,我与一些“之前”和重组respond_to?
输出“后”,看看它卡住。
def respond_to?(name, *args)
return true if super(name, *args)
puts "before (#{name})"
result = parent_association.respond_to?(name)
puts "after"
result
end
运行时,似乎各种回调和属性运行方法如预期,有单前和呼叫后每个:
before (_run__374051839217347232__initialize__1707831318230746190__callbacks)
after
before (_run__374051839217347232__validation__1707831318230746190__callbacks)
after
before (_run__374051839217347232__validate__1707831318230746190__callbacks)
after
before (_run__374051839217347232__save__1707831318230746190__callbacks)
after
before (_run__374051839217347232__create__1707831318230746190__callbacks)
after
before (created_at)
after
before (created_on)
after
...
但是,任何时候我看到查找回调,那似乎正在陷入一个死循环:
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
before (_run__374051839217347232__find__1707831318230746190__callbacks)
...
SystemStackError: stack level too deep
如果我砍我的respond_to?
,那么一切似乎顺利运行:
def respond_to?(name, *args)
return true if super(name, *args)
return false if name =~ /^_run_.*_find_.*_callbacks$/
parent_association.respond_to?(name)
end
我在做什么错,我似乎需要这个黑客?我该如何避免它?
如果你使用精确的语言,它会更清晰。 'parent_association_name'不是一个变量,我认为'employee'总是被定义的,尽管它可能不会被加载。不确定你实际上是否指“回调”。我仍然不确定你所描述的不是我所说的,也不是你如何修正它。 – 2012-04-09 20:05:52