Grouped Select in Rails
Edit
Correction, since you're using Arrays you'll need grouped_options_for_select
Example:
grouped_options = [
['Group 1',
["Item 1", "Item 2", "Item 3"]],
['Group 2',
["Item 1", "Item 2", "Item 3", "Item 4"]]
]
grouped_options_for_select(grouped_options)
Prints the following:
<optgroup label="Group 1">
<option value="Item 1">Item 1</option>
<option value="Item 2">Item 2</option>
<option value="Item 3">Item 3</option>
</optgroup>
<optgroup label="Group 2">
<option value="Item 1">Item 1</option>
<option value="Item 2">Item 2</option>
<option value="Item 3">Item 3</option>
<option value="Item 4">Item 4</option>
</optgroup>
Note that you have to provide your own select tags to wrap this. There is no select function that will do grouping for you, just this method.
You should get over your reticence. The Rails Way (tm) to do what you ask is to use select_tag with grouped_options_for_select:
<%= select_tag "foo[bar]",
grouped_options_for_select(@bars) %>
This is what happens when you go off the beaten path with Rails. :)
Here's a reference I just found on google:
http://www.ruby-forum.com/topic/185407
Option Group in select tag using rails
I have added one field called type in template model.Type field has radio button built_in and custom so when I create one template we choose radio button of that type.
Now, my dropdown for option select is look like this:
<%= select_tag :template ,grouped_options_for_select([['Built-In templates', @built_in.collect {|v| [ v.name, v.id ] }],['Custom', @custom.collect {|v| [ v.name, v.id ] }]]),{:prompt => t("please_select"),:class=>"form-control m-b-sm required"}%>
How can I have a multiple grouped select with simple_form?
I figured it out on my own.
This produced the correct output:
<%= f.association :tags, as: :grouped_select, collection: TagGroup.all, group_method: :tags, input_html: { :multiple => true } %>
The key part being:
input_html: { :multiple => true }
Rails 4 JOIN GROUP BY and SELECT
Would the following work for you?
User.joins(:orders)
.select("users.*, max(orders.created_at) as most_recent, count(orders.id) as orders_count")
.group('users.id')
Taking the max
of order.created_at
should give you the date of the most recent order. I don't think you want to have your select
as part of has_many
orders, since you're looking for a list of users, not a list of orders. If you'd a method that returns this active record query, assuming you'll use it more than once, you can add the following to your User
model.
def self.with_order_info
self.joins(:orders)
.select("users.*, max(orders.created_at) as most_recent, count(orders.id) as orders_count")
.group('users.id')
end
And then, you can call that method anywhere using:
@users = User.with_order_info
As a further note (to be 100% clear), you should keep your association to orders as:
has_many :orders
Setting up grouped options for the f.select form helper
You can do it mapping the collection and then grouping it by a value in the array, for example
<%= f.select(:location_id, grouped_options_for_select(Location.all.map{|l| [l.name, l.category_name, l.id]}.group_by { |c| c[1] }), {include_blank: "Select one..."}, {:class => 'grouped_select',id:"location_grouped"}) %>
This will create the select, grouped by category_name.
Use grouped_collection_select to group a model by enum
The grouped_collection_select
method is not the best tool for your needs because it really deals with associated records of a main record, whereas you, if I understand correctly, simply want to add all Conversation
records to a select tag, but grouped by its attribute, not association.
You can easily construct the grouped options manually, though. I'd put this code into a helper not to clutter the view template too much:
# app/helpers/conversations_helper.rb
module ConversationsHelper
def grouped_conversations_options_for_select(selected_conversation_id = nil)
options = {}
Conversation.statuses.keys.each do |status|
options[status] = Conversation.with_status(status).pluck(:name, :id)
end
grouped_options_for_select(options, selected_conversation_id)
end
end
# app/view/show.html.erb
<%= select_tag :conversation_id, grouped_conversations_options_for_select(params[:conversation_id]) %>
The helper first constructs a hash with the following structure:
{
active: [[ conversation.id, conversation.name ], [...]],
archived: [[ conversation.id, conversation.name ], [...]],
}
This hash can be then passed to the grouped_options_for_select
which converts it to the <OPTIONS>
tags including proper <OPTGROUP>
tags. The helper also supports setting the currently selected value in the select options. Its output is then passed to the select tag in the view template.
For the helper to work, you also need to add the following scope to the Conversation
model:
# app/models/conversation.rb
scope :with_status, ->(status) { where(status: statuses[status]) }
How do I get grouped_collection_select to display within form.select?
For anybody else interested, the below syntax gave me the expected HTML output.
<%= form.grouped_collection_select(:category_id, Category.top_level, :sub_categories, :name, :id, :name,
{ prompt: 'Select a category'},
{ id: :product_category }) %>
Rails - grouped_options_for_select
The grouped_options_for_select
method indeed is the correct one.
Since you haven't provided code, this should result in the grouped options you want:
grouped_options_for_select [['Fruits', @fruits.collect {|v| [ v.name, v.id ] }],
['Veggies', @veggies.collect {|v| [ v.name, v.id ] }],
['Junk', @junk_food.collect {|v| [ v.name, v.id ] }]]
Which can be used to create the dropdown:
select_tag 'Food', grouped_options_for_select(...)
or with form_helper:
f.select :food_attribute, grouped_options_for_select(...)
Rails generate select with both options and option groups
This is hard to answer precisely without knowing what the data looks like, but I'm going to guess that you have something like this:
@grouped_options = [
["Some nil value label"],
["Option one", "1"],
["Option Group 1",
[
["Option one in group 1", "1:1"],
["Option two in group 1", "1:2"],
]
],
["Option Group 2",
[
["Option one in group 2", "2:1"],
["Option two in group 2", "2:2"],
]
],
]
With that, you have a couple options. In plain ERB, you can do it like this:
<%= select "thing", "some_attr" do %>
<% @grouped_options.each do |label, value_or_options| %>
<% if Array === value_or_options %>
<%= tag.optgroup options_for_select(value_or_options), label: label %>
<% else %>
<%= tag.option label, value: value_or_options %>
<% end %>
<% end %>
<% end %>
Personally, though, I would write a helper. The Enumerable#chunk
method splits an array into runs of values that return the same thing for the given block, making it easy to separate the grouped from the non-grouped items so we can use grouped_options_for_select
and options_for_select
, respectively:
def ungrouped_and_grouped_options_for_select(choices, selected_key = nil)
capture do
choices
.chunk {|_, choice_or_group| Array === choice_or_group }
.each do |is_group, choices_or_grouped_choices|
if is_group
concat grouped_options_for_select(choices_or_grouped_choices, selected_key)
else
concat options_for_select(choices_or_grouped_choices, selected_key)
end
end
end
end
You could then use it this:
<%= select "thing", "some_attr" do %>
<%= ungrouped_and_grouped_options_for_select(@grouped_options) %>
<% end %>
You can see both of these approaches in action on repl.it: https://repl.it/@jrunning/UnacceptablePlaintiveServer (see views/tests/index.html.erb
, controllers/tests_controller.rb
, and helpers/application_helper.rb
).
Related Topics
Set Ruby Variable If It Is Not Already Defined
How to Generate Links with Trailing Slash in Rails 3
How to Make Httparty Ignore Ssl
HTML Code Inside Buttons with Simple_Form
Why Does Ruby String#Split Not Treat Consecutive Trailing Delimiters as Separate Entities
Add Space After Commas Only If It Doesn't Already
Installing Postgresql on Ubuntu for Ruby on Rails
Connect to a Locally Built Jekyll Server Using Mobile Devices in the Lan
Create Custom HTML Helpers in Ruby on Rails
How to Copy File Across Buckets Using Aws-S3 or Aws-Sdk Gem in Ruby on Rails
Ruby - Digest::Digest Is Deprecated; Use Digest
Safe Navigation Operator (&.) for Nil
Ruby Mocha: Is There an Equivalent to Rspec-Mocks' #And_Call_Original