1

I have a list of states from a country, and I would like to display them a on a <select>. Since I am trying to show an icon that represents the flag of each state, I am using this JQuery plugin. Anyway, at this point this is a pure Rails question.

To use that plugin, I need to set a "data-image" attribute on each of option tags contained in this select.

What I have so far is:

<%= collection_select(:state, :code, @states, :code, 
:name, {"data-image" => lambda {|state| image_path("/flags/#{state.code}.png") }}) %>

I've tried in lots of ways to set the "data-image" attribute to each of option but so far the result is:

<select id="state_code" name="state[code]">
  <option value="foo">State Foo</option>
  <option value="bar" selected="selected">State Bar</option>
</select>

Therefore, I am not being successful to inject my "data-image" attribute. I've been searching for some light, and I saw this [api.rubyonrails] and the following example,

collection_select(:post, :category_id, Category.all, :id, :name, {:disabled => lambda{|category| category.archived? }})

that is basically what I am looking for and mine is pretty much the same thing but it does not work. I am using Rails 2.3.11. I will be thankful with suggestion.

Eduardo
  • 4,282
  • 2
  • 49
  • 63

2 Answers2

1

Check out the second answer to this Stackoverflow question.

Basically, it involves using the options_for_select helper to create the custom data prefixed attributes.

Community
  • 1
  • 1
Zajn
  • 4,078
  • 24
  • 39
  • thanks, I've upvoted your answer and posted the completed answer. At the point I saw your answer, I've already understood the options_for_select and data attributes problem on Rails 2. – Eduardo Jan 07 '13 at 20:28
  • I completely missed the fact that you're using Rails 2, my bad! I gotta start reading things more carefully. Glad you got things figured out though! – Zajn Jan 07 '13 at 22:02
  • no problems, your link would be the North to the solution if I had not seen that question before. Thanks a ton! Cheers! – Eduardo Jan 07 '13 at 22:17
0

So, I ended up solving the problem, following is the complete solution. As far as I understood, since I am using Rails 2.3 there are not helpers to support data prefixed attributes. It turned out that I needed to use the Rails 3 options_for_select helpers as pointed out by this answer. As a side note, instead of using the msDropDown plugin, and I ended up using the ddSlick. Also, instead of using collection_select, I've used a select_tag. Then basically what you have to have is:

rails_overrides.rb

# https://stackoverflow.com/a/13962481/914874
module RailsOverrides
  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
end

application_helper.rb

module ApplicationHelper
  include RailsOverrides
end

index.html.erb

<%= select_tag(:state, options_for_select (states.map { |state| [state.name, state.code, {"data-imagesrc" => image_path("flags/#{state.code}.png"), "data-description" => "Data from #{state.name}"}]}, current_state.code)) %>

Here, current_state is the state to be selected as the default option. For instance, I store it on a session variable, but for the sake of simplicity it could be a @current_state.

Another way to solve that would be to use a modified version of options_from_collection_for_select_with_data so it would no be necessary to expose the map.

Community
  • 1
  • 1
Eduardo
  • 4,282
  • 2
  • 49
  • 63