今天我遇到了红宝石真正有趣的问题。我有一个模块/轨道问题:
module BreakCacheModule
extend ActiveSupport::Concern
module ClassMethods
def breakable_cache_for(method_name, &block)
method_name = method_name.to_sym
set_breakable_cache_proc(method_name, block)
define_breakable_cache_method(method_name)
end
def define_breakable_cache_method(method_name)
instance_eval(
"def #{method_name}
# here will be Rails.cache.fetch block around line below once I figure out this problem
@_break_cache_procs[#{method_name}].call # !!! this line will cause an issue
end"
)
end
def set_breakable_cache_proc(method_name, block)
@_break_cache_procs ||={}
@_break_cache_procs.merge!({method_name => block})
@_break_cache_procs
end
end
end
在我的模特中
class Client < ActiveRecord::Base
include BreakCacheModule
breakable_cache_for :all_client_ids do
Client.pluck :id
end
end
如此优秀,但一旦我进入控制台(或运行我的规格),问题就会出现
Client.all_client_ids
# SystemStackError: stack level too deep
但是当我这样做时:
Client.instance_variable_get("@_break_cache_procs")[:all_client_ids].call
#=> [1,2,3]
功能完全相同,唯一的区别是我没有从instance_eval调用proc。
我错过了什么吗?
我的ruby ruby-2.0.0-p247和Rails 3.2.14
感谢您的帮助
接受后更新
总结一下,我从两个地方得到了这个错误:
"def #{method_name}
Rails.cache.fetch(#{method_name.to_s}) do # method_name should be in quotes
@_break_cache_procs[#{method_name}].call # missing colon ...look on answer
end
end"
所以代码看起来应该是这样的
instance_eval(
"def #{method_name}
Rails.cache.fetch('#{method_name.to_s}') do
@_break_cache_procs[:#{method_name}].call
end
end"
)
答案 0 :(得分:3)
传递给instance_eval
的字符串实际上是:
"def all_client_ids
@_break_cache_procs[all_client_ids].call
end"
您可能已经注意到了这个问题:缺少冒号。
这应该是正确的代码:
def define_breakable_cache_method(method_name)
instance_eval(
"def #{method_name}
# here will be Rails.cache.fetch block around line below once I figure out this problem
@_break_cache_procs[:#{method_name}].call # !!! this line will cause an issue
end"
)
end