如何找到运行时调用 Ruby 方法的位置?
这种特定方法导致应用程序中断:
# needed becasuse of a rails bug
def to_s
"#{self.class.name.underscore}__#{object_id}"
end
出现以下错误:
ActionView::TemplateError (`@content_for_details_view_builder__2234321380' is not allowed as an instance variable name) in app/views/shared/_details_view.haml:
基本上,这是导致上述异常的代码执行:
# controller
def new
@view_mode = :new
template = "new"
render template, :layout => false
end
# new.haml
- details_view @user do |b, f|
# build_helper
def details_view(model, options = {}, &block)
# instantiate OptionsWrapper passing a hash of key/value pairs, in this case
# an empty hash. OptionsWrapper contains a method_missing method so when we
# invoke mode on our instance of OptionsWrapper, since it does not contain
# instance method of mode, it invokes method_missing and we set a number of
# methods on fly.
options = OptionsWrapper.new(options)
options.mode ||= @view_mode
model_name = model.class.model_name.singular.dasherize
options.dom_id = "#{model_name}-details-view"
# we instantiate DetailsViewBuilder passing in a few arguments (e.g. new,
# ActionView, user) to the constructor method.
builder = DetailsViewBuilder.new(options.mode, self, model)
options.html ||= {}
options.html[:id] ||= nil
options.html[:class] = "x-#{options.mode} #{options.html[:class]}".strip
render :layout => "shared/details_view", :locals => {:builder => builder,
:model => model, :options => options}, &block
end
#details_view_builder
class DetailsViewBuilder
attr_accessor :mode, :template, :model, :form
def initialize(mode, template, model)
@mode, @template, @model = mode, template, model #new, ActionView, user
end
def to_s
# here's the method causing error!
"#{self.class.name.underscore}__#{object_id}"
end
end
# we then render the details_view passing in some locals as shown a
# few lines above:
.details-dialog{:id => options.dom_id }
case options.mode
- when :new
- form_for model, options.slice(:url, :html) do |form|
= yield builder, form
我 100% 确定 to_s 方法导致了错误。我不确定它在哪里被调用,但它导致了这个错误。注意上面它产生了构建器变量。该构建器变量包含具有此方法的类。我需要找到一种更好的方法来检查元素,这样我就可以透明地看到调用堆栈,并且给定一个方法,我知道它在哪里被调用。奇怪的是,此方法在我的本地计算机上有效,但在服务器上的生产中导致错误。这是回溯的花絮:
ActionView::TemplateError
(`@content_for_details_view_builder__-626960428' is not allowed as an
instance variable name) in app/views/shared/_details_view.haml:
searchlogic (2.4.27) lib/searchlogic/rails_helpers.rb:75:in
`fields_for'
searchlogic (2.4.27) lib/searchlogic/rails_helpers.rb:64:in
`form_for'
app/helpers/builders_helper.rb:68:in `details_view'
/home/app-sptr/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/1.8/benchmark.rb:308:in
`realtime'
app/other/restful_component.rb:488:in `new_html'
app/other/restful_component.rb:73:in `new'
app/other/restful_component.rb:72:in `new'
/home/app-sptr/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/1.8/benchmark.rb:308:in
`realtime'
rack (1.1.2) lib/rack/head.rb:9:in `call'
rack (1.1.2) lib/rack/methodoverride.rb:24:in `call'
rack (1.1.2) lib/rack/lock.rb:11:in `call'
rack (1.1.2) lib/rack/lock.rb:11:in `synchronize'
rack (1.1.2) lib/rack/lock.rb:11:in `call'
我也在这里提出了问题,但对答案不满意: http://www.ruby-forum.com/topic/1641800#new
This specific method is causing application to break:
# needed becasuse of a rails bug
def to_s
"#{self.class.name.underscore}__#{object_id}"
end
with the following error:
ActionView::TemplateError (`@content_for_details_view_builder__2234321380' is not allowed as an instance variable name) in app/views/shared/_details_view.haml:
Basically here's the code execution that leads up to the above exception:
# controller
def new
@view_mode = :new
template = "new"
render template, :layout => false
end
# new.haml
- details_view @user do |b, f|
# build_helper
def details_view(model, options = {}, &block)
# instantiate OptionsWrapper passing a hash of key/value pairs, in this case
# an empty hash. OptionsWrapper contains a method_missing method so when we
# invoke mode on our instance of OptionsWrapper, since it does not contain
# instance method of mode, it invokes method_missing and we set a number of
# methods on fly.
options = OptionsWrapper.new(options)
options.mode ||= @view_mode
model_name = model.class.model_name.singular.dasherize
options.dom_id = "#{model_name}-details-view"
# we instantiate DetailsViewBuilder passing in a few arguments (e.g. new,
# ActionView, user) to the constructor method.
builder = DetailsViewBuilder.new(options.mode, self, model)
options.html ||= {}
options.html[:id] ||= nil
options.html[:class] = "x-#{options.mode} #{options.html[:class]}".strip
render :layout => "shared/details_view", :locals => {:builder => builder,
:model => model, :options => options}, &block
end
#details_view_builder
class DetailsViewBuilder
attr_accessor :mode, :template, :model, :form
def initialize(mode, template, model)
@mode, @template, @model = mode, template, model #new, ActionView, user
end
def to_s
# here's the method causing error!
"#{self.class.name.underscore}__#{object_id}"
end
end
# we then render the details_view passing in some locals as shown a
# few lines above:
.details-dialog{:id => options.dom_id }
case options.mode
- when :new
- form_for model, options.slice(:url, :html) do |form|
= yield builder, form
I'm 100 percent sure that the to_s method is causing the error. I am not sure though where it is being called that it is causing this error. Notice above it yields the builder variable. That builder variable contains the class that has this method. I need to find a better way to inspect elements so I can see the callstack transparently and that given a method, I know where it's called. Oddly enough, this method works on my local machine but causes error on production on server. Here's a tidbit of the backtrace:
ActionView::TemplateError
(`@content_for_details_view_builder__-626960428' is not allowed as an
instance variable name) in app/views/shared/_details_view.haml:
searchlogic (2.4.27) lib/searchlogic/rails_helpers.rb:75:in
`fields_for'
searchlogic (2.4.27) lib/searchlogic/rails_helpers.rb:64:in
`form_for'
app/helpers/builders_helper.rb:68:in `details_view'
/home/app-sptr/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/1.8/benchmark.rb:308:in
`realtime'
app/other/restful_component.rb:488:in `new_html'
app/other/restful_component.rb:73:in `new'
app/other/restful_component.rb:72:in `new'
/home/app-sptr/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/1.8/benchmark.rb:308:in
`realtime'
rack (1.1.2) lib/rack/head.rb:9:in `call'
rack (1.1.2) lib/rack/methodoverride.rb:24:in `call'
rack (1.1.2) lib/rack/lock.rb:11:in `call'
rack (1.1.2) lib/rack/lock.rb:11:in `synchronize'
rack (1.1.2) lib/rack/lock.rb:11:in `call'
I also asked question here but wasn't satisfied with answer:
http://www.ruby-forum.com/topic/1641800#new
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用
caller()
的建议可以很好地找出某个方法的堆栈跟踪。不过,我也会分享(我认为的)您问题的解决方案。to_s
方法返回一个用于动态设置实例变量的字符串。DetailsViewBuilder
的object_id
是变量名称的一部分。对象 ID 表示对象在内存中的位置。与直觉相反,对象的object_id
有时可能是负整数。这种情况是否发生也可能取决于平台。这解释了为什么您只在生产中看到此错误。负对象 ID 会导致实例变量名称变为类似于@content_for_details_view_builder__-626960428
的内容,其中包含破折号。 破折号不允许作为 Ruby 中标识符的一部分。因此出现了错误。您似乎在某处使用
DetailsViewBuilder
的实例作为content_for
的参数,对吗?或者它可能会在您正在使用的某些库中间接发生。无论如何,如果这是正确的行为,并且您想要的只是避免实例变量名称错误,那么修复很简单。将
object_id
更改为object_id.abs
以保证实例变量从不包含破折号:The suggestion to use
caller()
is fine for figuring out the stack trace from a certain method. However, I'll also share (what I think is) the solution to your problem.The
to_s
method returns a string that is used to set an instance variable dynamically. TheDetailsViewBuilder
'sobject_id
is part of the variable name. The object ID represents the object's location in memory. Contrary to intuition, theobject_id
of an object may sometimes be negative integer. Whether or not this happens may also be platform-dependant. This explains why you are only seeing this error in production. The negative object ID causes the instance variable name to become something like@content_for_details_view_builder__-626960428
, which contains a dash. Dashes are not allowed as part of identifiers in Ruby. Hence the error.It seems that you are using an instance of
DetailsViewBuilder
as argument tocontent_for
somewhere, is that right? Or it might happen indirectly, in some library you are using.In any case, if this is the correct behaviour, and all you want is to avoid the instance variable name error, then the fix is simple. Change
object_id
toobject_id.abs
to guarantee that the instance variable never contains a dash:建议使用
caller()
在您发布的链接中,实际上非常好。该文档有一个不错的示例,但您似乎错过了这部分:
基本上,
caller()
是从未处理的异常中获得的堆栈跟踪的核心,只有您可以说出它应该显示多少行。The suggestion to use
caller()
in the link you posted, is actually very good.The docs have a decent example, but what you seem to have missed was this part:
Basically
caller()
is the guts of a stack trace you'd get from an unhandled exception, only you can say how many lines it should display.