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

AKW*_*KWF 1 ruby ruby-on-rails ruby-on-rails-2 ruby-2.3

Rails 2.3我正在新虚拟机上运行旧版(是的,我知道)应用程序。它正在运行Ruby v2.3.1。我已经进行了所有建议的更改,以使这个旧应用程序在此版本上运行。除了这段代码之外,一切都运行得很好,而且速度更快。这段代码来自旧书Advanced Recipes for Railserror_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 %>
Run Code Online (Sandbox Code Playgroud)

如果我删除构建器参数,此代码可以正常工作。这是来自的代码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
Run Code Online (Sandbox Code Playgroud)

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

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

看着代码,不知道怎么改。

我知道我必须使用显式参数调用 super,但我尝试了以下方法:

super(field, options)
Run Code Online (Sandbox Code Playgroud)

我得到:

wrong number of arguments (given 2, expected 4..6)
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

build_shell(field, options) do
  super(*args)
end
Run Code Online (Sandbox Code Playgroud)

但我得到:

undefined method `map' for :id:Symbol
Did you mean?  tap
Run Code Online (Sandbox Code Playgroud)

看起来它正在寻找collection列表中的第二个属性*args。但这是第一个。如果我field作为第一个参数传递,我会得到一个Stack Level Too Deep.

Jör*_*tag 5

super如果没有参数列表,则重新发送当前消息,在超类处启动消息调度,传递与传递给当前方法完全相同的参数。

\n\n

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

\n\n

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

\n\n
\n

看着代码,不知道怎么改。

\n
\n\n

简单:由于super没有参数列表,隐式传递的参数与传递的参数完全相同,因此显式等效的方法是将参数列表从方法定义复制并粘贴到 的参数列表中super。在本例中,方法定义为define_method(name) do |field, *args| \xe2\x80\xa6 end,因此参数列表为(field, *args),您只需将其复制到 的参数列表中supersuper(field, *args),您只需将其复制到的

\n\n

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

\n