我正在構建一個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