Rails options_from_collection_for_select with custom attributes for each option

You probably already know that you can use options_from_collection_for_select helper method generate <option></option> from a collection. If you are unaware of it, you can check this api documentation.

It helped me greatly until I needed some custom attributes to each <option></option> which will be used by jQuery for doing some tasks in UI level. Custom attributes will help me by reducing server calls for getting those information. However, I did not find a way set custom attributes with the above helper method. So, I’ve made a basic version of my own (if you prefer, you can override the original method). Put the following method in your helper file (may be in application_helper.rb).

def options_from_collection_for_select_with_data(collection, value_method, text_method, selected = nil, data = {})
    options = collection.map do |element|
      [element.send(text_method), element.send(value_method), data.map do |k, v|
        {"data-#{k}" => element.send(v)}
    selected, disabled = extract_selected_and_disabled(selected)
    select_deselect = {}
    select_deselect[:selected] = extract_values_from_collection(collection, value_method, selected)
    select_deselect[:disabled] = extract_values_from_collection(collection, value_method, disabled)

    options_for_select(options, select_deselect)

Now, when you need to use this method, call it as below:

options_from_collection_for_select_with_data(@blogs, :id, :title, nil,
  {:'post-type' => :type, :'post-slug' => :slug})

Note that, this will call the type and slug method of your object. It will not directly use the :type and :slug as your attributes value. Consider @blogs has only one blog item as follows:

{:id => 101, :title => 'Test Blog 1', :type => 'post', :slug => 'test-blog-1'}

so, the option will be like:

<option value="101" data-type="post" data-slug="test-blog-1">Test Blog 1</option>

As you see, data- will be prepended to your attribute names. So, you do not need to add them yourself.

This is basic version of what I’ve implemented and surely can be improved. Suggest me please.