Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom data attribute for grouped_collection_select

grouped_collection_select accepts nine parameters, including an options attribute. How do you add a custom attribute in options, a data tag, to be used when an option is selected?

The select is coded as of now as:

= f.grouped_collection_select :course_id, Discipline.order(:name), :courses, :name, :id, :display

I want to add a custom data attribute so that the output is like:

<select id="enrollment_course_id" name="enrollment[course_id]">
    <option selected="selected" value="7" data-duration=8>Introduction to Guitar (8 weeks)</option>
    <option value="8" data-duration=8>Strings 1-3 (8 weeks)</option>
    <option value="9" data-duration=10>Strings 4-6 (10 weeks)</option>
    <option value="10" data-duration=12>Basic Chords (12 weeks)</option>
</select>

How do we generate the custom attribute programmatically?

like image 886
Subhash Avatar asked Mar 03 '26 22:03

Subhash


1 Answers

There seems to be no nice and properly documented way to do this.

Solution 1. use non fully documented features of grouped_collection_select:

f.grouped_collection_select :course_id, Discipline.order(:name), :courses_with_duration_data, :name, ->(el){el.first.id}, ->(el){el.first.display}

Where you need to implement courses_with_duration_data like this:

class Discipline
  has_many :courses
  def courses_with_duration_data
    courses.map {|course| [course,{data: {duration: course.duration}}]}
  end
end

It relies on that if you pass array of arrays to options_for_select the hash within the arrays will be treated as html options.

It has a disadvantage of putting view related methods to your model. And it something that might break with future rails releases as this use is not documented on grouped_collection_select, so you're probably better of generating the options yourself.

Solution 2. Reimplement options yourself:

Reimplement custom option_groups_from_collection_for_select in a helper. This could look something like this:

def options_for_disciple_with_courses(disciplines)
  disciplines.map do |discipline|
    option_tags = options_for_select(
      discipline.courses.map {|course| [course.display, course.id, {data: {duration: course.duration}}]}
    )
    content_tag(:optgroup, option_tags, label: discipline.name)
  end.join.html_safe
end

And your view would became:

f.select :course_id, options_for_disciple_with_courses(Discipline.order(:name))
like image 128
mfazekas Avatar answered Mar 06 '26 02:03

mfazekas