grouped_collection_select should accept a query.

Hello everyone

I have some thoughts about the FormOptionsHelper method grouped_collection_select (and the options version: options_groups_from_collection_for_select), that i would like to share and hopefully this will turn into a PR when i have time and got some feedback.

See ActionView::Helpers::FormOptionsHelper.

The normal collection_select method takes a collection of records (could be any AR relation) and then creates the option tags from that. The grouped_collection_select also takes a collection, but it creates the optgroub tags from this collection, and then uses a relation from this collection to create the option tags. This means that you have very little flexibility in choosing which option tags that are created in the end. Let me give a example:

I have this select

collection_select(:post, :tag_id, Tag.usable_by(current_user), :id, :name)

Now i want to make these tags grouped by a tag category:

grouped_collection_select(:post, :tag_id, Category.all, :tags, :name, :id, :name)

This would work, but it will now list ALL tags not only those that is “usable by current user”. Instead i would need to do something like this:

collection = Tag.usable_by(current_user).group_by{|t| category.name}.map{|c,t| [c, t.map{|t| [t.name, t.id]}}

select(:post, :tag_id, grouped_options_for_select(collection) )

I often come across this problem, whereas I have never experienced that i needed to constrain the optgroup (here Category), and im not the only one (here is a example from stackoverflow: ruby on rails - How to seperate multiple select box values based on category and display as group? - Stack Overflow, where i help someone with the exact same problem)

In my opinion would the best solution be something like this:

grouped_collection_select(object, method, collection, group_by_method, group_by_label_method, option_key_method, option_value_method, options = {}, html_options = {})

So the previous example would look something like this:

grouped_collection_select(:post, :tag_id, Tag.usable_by(current_user), :category_id, :category_name, :id, :name)

However this would not be backward compatible. Another solution would be to allow a proc as group_method so we could do something like this:

grouped_collection_select(:post, :tag_id, Category.all, proc{|c| c.tags.usable_by(current_user)}, :name, :id, :name)

What do you think, any thoughts? Or is this case to special?

Best Regards Johan Frølich / @jokklan