【问题标题】:ruby on rails f.select options with custom attributesruby on rails f.select 具有自定义属性的选项
【发布时间】:2011-06-30 11:42:22
【问题描述】:

我有一个表单选择语句,如下所示:

= f.select :country_id, @countries.map{ |c| [c.name, c.id] }

这会导致以下代码:

...
<option value="1">Andorra</option>
<option value="2">Argentina</option>
...

但我想在我的选项中添加一个自定义 HTML 属性,如下所示:

...
<option value="1" currency_code="XXX">Andorra</option>
<option value="2" currency_code="YYY">Argentina</option>
...

【问题讨论】:

  • Rails 不提供该功能,您必须创建一个助手来创建该标记。另外,请记住,您提到的示例不是有效的 HTML。
  • 我知道,我的例子不是有效的 html... 我想我必须改变我的方式才能得到我想要的结果,thk!

标签: ruby-on-rails select attributes


【解决方案1】:

Rails 可以使用现有的 options_for_select 助手添加自定义属性来选择选项。您几乎在问题的代码中就正确了。使用 html5 数据属性:

<%= f.select :country_id, options_for_select(
    @countries.map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] }) %>

添加初始选择:

<%= f.select :country_id, options_for_select(
    @countries.map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] }, 
    selected_key = f.object.country_id) %>

如果你需要分组选项,你可以使用 grouped_options_for_select 帮助器,像这样(如果@continents 是一个大陆对象数组,每个对象都有一个国家方法):

<%= f.select :country_id, grouped_options_for_select(
    @continents.map{ |group| [group.name, group.countries.
    map{ |c| [c.name, c.id, {'data-currency_code'=>c.currency_code}] } ] }, 
    selected_key = f.object.country_id) %>

信用应该归于 paul @ pogodan,他发布的不是在文档中而是通过阅读 rails 源代码来发现这一点的。 https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select

【讨论】:

    【解决方案2】:

    只有 Rails 3 支持额外的属性哈希。

    如果您使用的是 Rails 2.x,并且想要覆盖 options_for_select

    我基本上只是复制了 Rails 3 代码。您需要重写这 3 个方法:

    def options_for_select(container, selected = nil)
        return container if String === container
        container = container.to_a if Hash === container
        selected, disabled = extract_selected_and_disabled(selected)
    
        options_for_select = container.inject([]) do |options, element|
          html_attributes = option_html_attributes(element)
          text, value = option_text_and_value(element)
          selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
          disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
          options << %(<option value="#{html_escape(value.to_s)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{html_escape(text.to_s)}</option>)
        end
    
        options_for_select.join("\n").html_safe
    end
    
    def option_text_and_value(option)
      # Options are [text, value] pairs or strings used for both.
      case
      when Array === option
        option = option.reject { |e| Hash === e }
        [option.first, option.last]
      when !option.is_a?(String) && option.respond_to?(:first) && option.respond_to?(:last)
        [option.first, option.last]
      else
        [option, option]
      end
    end
    
    def option_html_attributes(element)
      return "" unless Array === element
      html_attributes = []
      element.select { |e| Hash === e }.reduce({}, :merge).each do |k, v|
        html_attributes << " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\""
      end
      html_attributes.join
    end
    

    有点乱,但这是一个选择。我将此代码放在名为RailsOverrides 的帮助模块中,然后将其包含在ApplicationHelper 中。如果你愿意,你也可以做一个插件/gem。

    一个问题是,要利用这些方法,您必须始终直接调用options_for_select。诸如

    之类的快捷方式
    select("post", "person_id", Person.all.collect {|p| [ p.name, p.id, {"data-stuff"=>"html5"} ] })
    

    将产生旧的结果。相反,它应该是:

    select("post", "person_id", options_for_select(Person.all.collect {|p| [ p.name, p.id, {"data-stuff"=>"html5"} ] }))
    

    同样不是一个很好的解决方案,但获得如此有用的数据属性可能是值得的。

    【讨论】:

      【解决方案3】:

      你可以这样做:

      = f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }
      

      【讨论】:

      • 正确,但已在 Anatortoise House 的回答中提到。
      • 接受的答案没有说明使用 ruby​​ 的自定义属性。这个确实如此,因此我觉得它更好,因为它是第一个显示如何通过 ruby​​ 进行操作的答案。
      【解决方案4】:

      我也遇到了这个问题,并创建了“enhanced_select”Ruby Gem 来解决这个问题。你可以在这里找到它:

      https://github.com/bkuhlmann/enhanced_select

      【讨论】:

      • 这个链接到 github.com 上的 404 页面
      【解决方案5】:

      这在 Rails 中无法直接实现,您必须创建自己的助手来创建自定义属性。也就是说,可能有两种不同的方法可以实现您想要的:

      (1) 在 HTML5 中使用自定义属性名称。 在 HTML5 中,您可以使用 custom attribute names,但必须在它们前面加上 'data-'。这些自定义属性不会随您的表单一起提交,但它们可用于在 Javascript 中访问您的元素。如果您想完成此操作,我建议您创建一个生成如下选项的助手:

      <option value="1" data-currecy-code="XXX">Andorra</option>
      

      (2) 使用带有自定义拆分的值来提交额外的数据。如果您真的想提交货币代码,我建议您创建这样的选择框:

      = f.select :country_id, @countries.map{ |c| [c.name, "#{c.id}:#{c.currency_code}"] }
      

      这应该会生成如下所示的 HTML:

      <option value="1:XXX">Andorra</option>
      <option value="2:YYY">Argentina</option>
      

      然后您可以在控制器中解析:

      @id, @currency_code = params[:country_id].split(':')
      

      【讨论】:

      • 很好的答案。我选择了第 1 种方法,并在博客中记录了我是如何制作助手的,以防它帮助其他人。 redguava.com.au/2011/03/…
      • 同意其他评论者——请参阅下面 Anatortoise 的回答!
      • >>>>>>>>>>>>>错误答案...继续滚动
      • 这在 Rails 中是直接可行的。见:stackoverflow.com/a/9076805/380607
      • 潘,请删除这个误导性的答案。
      猜你喜欢
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-07-27
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多