grouped_collection_select - group_method 从 Rails 3 变为 4

grouped_collection_select - group_method changes from Rails 3 to 4

我们正在从 Rails 3.2.13 迁移到 Rails 4.0.13。

我们使用 Rails 助手 grouped_collection_select 来嵌套 <optgroup>s。

我注意到从 Rails 3.2.13 到 4.0.2 有源更改。

http://apidock.com/rails/v4.0.2/ActionView/Helpers/FormOptionsHelper/grouped_collection_select

我们目前使用的方法无效。

这是我们的代码:

<%= f.grouped_collection_select :location_id, @participating_businesses, :"active_locations(#{current_user.id})", :name, :id, :name, {prompt: t('.prompt_select_location')}, class: 'location-selector form-control' %>

这里是错误:

ActionView::Template::Error (undefined method `active_locations(7)' for #<ParticipatingBusiness:0x005583478f1f90>):

现在很明显他们已经改变了发送方法的方式。

我猜测目前他们正在获取 group_method 选项并将其直接放入 send(:group_method),这解释了上述错误。

但是,我如何将参数传递给依赖于会话(又名 current_user)的 group_method

查看源码,我认为不太可能。

http://www.rubydoc.info/docs/rails/4.1.7/ActionView/Helpers/Tags/GroupedCollectionSelect#initialize-instance_method

我是否应该考虑重新编写它以实现我们的目标,而无需帮助或更多手动操作?

有没有人运行遇到同样的问题?

这越来越令人沮丧。

我已经深入研究了 4.0.13 的 Rails 源代码和有问题的函数 option_groups_from_collection_for_select

  def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
    collection.map do |group|
      option_tags = options_from_collection_for_select(
        group.send(group_method), option_key_method, option_value_method, selected_key)

      content_tag("optgroup".freeze, option_tags, label: group.send(group_label_method))
    end.join.html_safe
  end

https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/actionview/lib/action_view/helpers/form_options_helper.rb#L455

直接发送method_groupsend

按照 Taryn East 的建议,我尝试制作 group_method 一个符号数组和该方法的一个参数。

然而这会引发 TypeError - [:accessible_locations, 15] is not a symbol.

这是由 send 提出的,因为这个数组需要 splat 运算符,在 send 调用中,作为方法参数。

现在这提出了一个重要的问题,即我们将如何回答最初的问题。

这个之前是怎么工作的?

在 Github 上查看旧 Rails 版本的源代码没有显示出任何差异,所以我逐步查看了代码并发现了这个:

421: def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
422:   collection.map do |group|
423:     group_label_string = eval("group.#{group_label_method}")
424:     "<optgroup label=\"#{ERB::Util.html_escape(group_label_string)}\">" +
425:       options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) +
426:       '</optgroup>'
427:   end.join.html_safe
428: end

以前就是这样。

因为它是 eval-ing 整个 group.group_method 方法代码,它不会引发 undefined method - method_name(args).

所以答案是,是的,需要重写。

我通过使用 grouped_options_for_select 帮助程序并构建数组来解决这个问题。

http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/grouped_options_for_select