ruby on Rails f.select 具有自定义属性的选项

发布于 2024-10-18 16:58:19 字数 464 浏览 1 评论 0原文

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

= 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>
...

I have a form select statement, like this:

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

Which results in this code:

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

But I want to add a custom HTML attribute to my options, like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(5

探春 2024-10-25 16:58:19

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 帮助器,如下所示(如果 @Continues 是一个大陆对象数组,每个对象都有一个国家方法):

<%= 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 源代码。

Rails CAN add custom attributes to select options, using the existing options_for_select helper. You almost had it right in the code in your question. Using html5 data-attributes:

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

Adding an initial selection:

<%= 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) %>

If you need grouped options, you can use the grouped_options_for_select helper, like this (if @continents is an array of continent objects, each having a countries method):

<%= 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) %>

Credit should go to paul @ pogodan who posted about finding this not in the docs, but by reading the rails source. https://web.archive.org/web/20130128223827/http://www.pogodan.com/blog/2011/02/24/custom-html-attributes-in-options-for-select

古镇旧梦 2024-10-25 16:58:19

您可以按如下方式执行此操作:

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

You could do this as follows:

= f.select :country_id, @countries.map{ |c| [c.name, c.id, { 'data-currency-code' => c.currency_code} ] }
栀梦 2024-10-25 16:58:19

直接使用 Rails 是不可能实现这一点的,您必须创建自己的帮助器来创建自定义属性。也就是说,可能有两种不同的方法来实现您想要的:

(1) 在 HTML5 中使用自定义属性名称。 在 HTML5 中,您可以使用 自定义属性名称,但必须以“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(':')

This is not possible directly with Rails, and you'll have to create your own helper to create the custom attributes. That said, there are probably two different ways to accomplish what you want:

(1) Using a custom attribute name in HTML5. In HTML5 you are allowed to have custom attribute names, but they have to be pre-pended with 'data-'. These custom attributes will not get submitted with your form, but they can be used to access your elements in Javascript. If you want to accomplish this, I would recommend creating a helper that generates options like this:

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

(2) Using values with custom splitting to submit additional data. If you actually want to submit the currency-code, I would recommend creating your select box like this:

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

This should generate HTML that looks like this:

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

Which you can then parse in your controller:

@id, @currency_code = params[:country_id].split(':')
離人涙 2024-10-25 16:58:19

额外的属性哈希仅在 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"} ] }))

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

The extra attributes hash is only supported in Rails 3.

If you're on Rails 2.x, and want to override options_for_select

I basically just copied the Rails 3 code. You need to override these 3 methods:

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

Kinda messy but it's an option. I place this code in a helper module called RailsOverrides which I then include in ApplicationHelper. You can also do a plugin/gem if you prefer.

One gotcha is that to take advantage of these methods you must always invoke options_for_select directly. Shortcuts like

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

will yield the old results. Instead it should be:

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

Again not a great solution, but it might be worth it to get to the ever so useful data-attribute.

终难遇 2024-10-25 16:58:19

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

https://github.com/bkuhlmann/enhanced_select

I ran into this issue as well and created the "enhanced_select" Ruby Gem to solve this problem. You can find it here:

https://github.com/bkuhlmann/enhanced_select

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