如何找到运行时调用 Ruby 方法的位置?

发布于 2024-11-05 07:44:49 字数 3409 浏览 7 评论 0原文

这种特定方法导致应用程序中断:

# 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷路的信 2024-11-12 07:44:49

使用 caller() 的建议可以很好地找出某个方法的堆栈跟踪。不过,我也会分享(我认为的)您问题的解决方案。

to_s 方法返回一个用于动态设置实例变量的字符串。 DetailsViewBuilderobject_id 是变量名称的一部分。对象 ID 表示对象在内存中的位置。与直觉相反,对象的 object_id 有时可能是负整数。这种情况是否发生也可能取决于平台。这解释了为什么您只在生产中看到此错误。负对象 ID 会导致实例变量名称变为类似于 @content_for_details_view_builder__-626960428 的内容,其中包含破折号。 破折号不允许作为 Ruby 中标识符的一部分。因此出现了错误。

您似乎在某处使用 DetailsViewBuilder 的实例作为 content_for 的参数,对吗?或者它可能会在您正在使用的某些库中间接发生。

无论如何,如果这是正确的行为,并且您想要的只是避免实例变量名称错误,那么修复很简单。将 object_id 更改为 object_id.abs 以保证实例变量从不包含破折号

def to_s
  "#{self.class.name.underscore}__#{object_id.abs}"
end 

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. The DetailsViewBuilder's object_id is part of the variable name. The object ID represents the object's location in memory. Contrary to intuition, the object_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 to content_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 to object_id.abs to guarantee that the instance variable never contains a dash:

def to_s
  "#{self.class.name.underscore}__#{object_id.abs}"
end 
看透却不说透 2024-11-12 07:44:49

建议使用 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:

The optional start parameter determines the number of initial stack entries to omit from the result.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文