如何更改此超级调用以显式传递参数?

时间:2016-07-20 20:32:00

标签: ruby-on-rails ruby ruby-on-rails-2 ruby-2.3

我在新VM上运行遗留Rails 2.3(是的,我知道)应用程序。它正在运行Ruby v2.3.1。我已经完成了所有建议的更改,以便在此版本上运行此旧应用。除了这段代码,一切都运行得很好,速度也快得多。此代码来自旧版Advanced Recipes for Rails,并且为error_handling_form_builder.rb

首先,这是表格声明:

<% form_for(:review, :builder => ErrorHandlingFormBuilder) do |f| %>
    <%= f.collection_select :system_id, @systems, :id, :name, { :include_blank => "Select a Standard"}, { :onchange => remote_function(:url => { :action => :makes }, :submit => :text, :method => 'post') } %>
    <div id="categoriesdiv">
    </div>
<% end %>

如果删除构建器参数,此代码可以正常工作。这是ErrorHandlingFormBuilder的代码:

helpers = field_helpers +
          %w(date_select datetime_select calendar_date_select time_select collection_select) +
          %w(collection_select select country_select time_zone_select) -
          %w(label fields_for)

helpers.each do |name|
  # We don't want to have a label for a hidden field
  next if name=="hidden_field"
  define_method name do |field, *args|
    options = args.detect {|argument| argument.is_a?(Hash)} || {}
    build_shell(field, options) do
      super # This call fails
    end
  end
end

上述对super的调用失败,并出现以下错误:

implicit argument passing of super from method defined by define_method()
is not supported. Specify all arguments explicitly.

查看代码,我不确定如何更改代码。

我知道我必须使用明确的参数调用super,但我尝试了这个:

super(field, options)

我得到了:

wrong number of arguments (given 2, expected 4..6)

我也尝试过:

build_shell(field, options) do
  super(*args)
end

但我明白了:

undefined method `map' for :id:Symbol
Did you mean?  tap

好像它在collection列表中寻找*args属性第2位。但它是第一个。如果我通过field作为第一个参数,我得到Stack Level Too Deep

1 个答案:

答案 0 :(得分:2)

没有参数列表的

super重新发送当前消息,在超类中启动消息调度,传递传递给当前方法的完全相同的参数。

在您的情况下,传递给当前方法的参数是(field, *args),因此没有参数列表的super会传递(field, *args),但不幸的是super没有参数列表在define_method内不起作用,因此您必须使用super(field, *args)显式传递参数。

这将调用带有name的超级类(field, *args)中给出的名称的方法,就像你在没有参数列表的情况下调用super一样。

  

查看代码,我不知道如何更改它。

简单:由于没有参数列表的super隐式传递参数与传递完全相同,因此显式等同于从方法中复制并粘贴参数列表定义到super的参数列表中。在这种情况下,方法定义为define_method(name) do |field, *args| … end,因此参数列表为(field, *args),您只需将其复制到super的参数列表中:super(field, *args)

传递不同的参数可能会或可能不会(并且可取),具体取决于方法的设计方式以及处理参数的方式,但总是工作。 (或者,换句话说:如果这不起作用,那么仅使用super的原始代码也不起作用。唯一的例外是当你想要传递一个块并且你没有捕获时阻塞到Proc,您必须修改方法签名以添加&blk参数。)