Rails generate select with both options and option groups - ruby-on-rails

Is it possible to generate select like:
<select>
<option value>Some nill value label</option>
<option value="1">Option one</option>
<optgroup label="Option Group 1" class="css-class-for-option-group-1">
<option value="1:1">Option one in group 1</option>
<option value="1:2">Option two in group 1</option>
</optgroup>
<optgroup label="Option Group 2" class="css-class-for-option-group-2">
<option value="2:1">Option one in group 2</option>
<option value="2:2">Option two in group 2</option>
</optgroup>
</select>
I tried to use the grouped_options_for_select, but I failed to find I way to pass both option and groups to it. Is there any way to achieve this? I am open to suggestions using SimpleForm as well.
Thanks!

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).

Assuming that the data is formatted as described by Jordan, you could also combine both 'select options' methods (options_for_select and grouped_options_for_select) by summing their return, like so:
<%= f.select :selected_ids, options_for_select([['Option 1', 1]]) + grouped_options_for_select([['Option Group 1', ['group1opt1', 11], ['group1opt2', 12]], ['Option Group 2', ['group2opt1', 21], ['group2opt2', 22]]]), {}, { class: 'class' } %>

Related

Rails Form select : preselect one choice

I have this rails code :
<% status_a = [ ["DRAFT", "DRAFT"], ["OPEN", "OPEN"], ["CLOSE", "CLOSE"] ] %>
<%= form_for(:dash_action, url: brokers_dashboard_path ) do |f| %>
<%= f.select(:select_status, options_for_select(status_a), {}, selected:'OPEN' %>
<% end %>
When it runs, it generates this HTML code :
<select selected="selected" name="dash_action[select_status]" id="dash_action_select_status">
<option value="DRAFT">DRAFT</option>
<option value="OPEN">OPEN</option>
<option value="CLOSE">CLOSE</option>
...
But what I expect is :
selected="OPEN" and not "selected"
Why the select method is not doing what I want ?
Try following code snippet, default value should be the parameter of options_for_select
f.select :select_status, options_for_select(status_a, 'OPEN')

Set a value for prompt in select Rails

I have a select dropdown in a form but was looking to set the prompt value as "0"
<%= f.select :image_size_id, options_for_select(#image_sizes.collect{ |i| [i.dimension] }), { prompt: "Please select a Print Size" }, id: 'image_size_select' %>
This generates
<select id="image_size_select" name="cart_item[image_size_id]">
<option value="">Please select a Print Size</option>
<option value="1">10x8</option>
<option value="2">A4</option>
<option value="3">A3</option>
<option value="4">A2</option>
</select>
Using jQuery I can do this
$(document).ready(function(){
$('#image_size_select option[value=""]').val('0')
});
But I was looking to do this using the select helper. Can it be set this way?
You'll need to add it to the array of values used by options_for_select instead of using the "prompt" option, which always sets a blank value. You should also make the array of sizes have two elements in each subarray: one for the displayed text and one for the value.
<% options = [["Please select a Print Size",0]] + #image_sizes.collect{ |i| [i.dimension, i.dimension] } %>
<%= f.select :image_size_id, options_for_select(options), id: 'image_size_select' %>
You can also try this.
<%= f.select :image_size_id, options_for_select([["Please select a Print Size", 0]] + #image_sizes.pluck(:dimension, :id)), {}, id: 'image_size_select' %>

Option Group in select tag using rails

I am getting values of #templates in my controller.
right now I have structure like this:
<%= select_tag :template ,options_from_collection_for_select(#templates,"id", "name"),{:prompt => "--Built In Templates--",:class=>"form-control m-b-sm required"}%>
But now I want to add option group in my select_tag
how can I create structure something like:
<%= select_tag :template ,grouped_options_for_select(['Built-In Templates',#templates.collect{|v| [v.name, v.id ] }],#templates),{:prompt => "please select",:class=>"form-control m-b-sm required"}%>
I want to create array of option group.like
<select>
<optgroup label="Built-In Templates">
<option value="id_default">default</option>
</optgroup>
<optgroup label="Custom Templates">
<option value="id_my template">my template</option>
</optgroup>
</select>
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"}%>

Collecting only a specific value and selecting as default

I have something like this as a select_tag :
<p><%= setting_select :ui_theme, My::Themes.themes.collect {|t| [t.name, t.id]}, :blank => :label_default, :label => :label_theme %></p>
Rite now it is collecting all the values and displaying but I want to collect only a specific value and make it default. This value has name = "Test".
Thus it should look like this and it should be default:
<option selected="selected" value="Test">Test</option>
Note : Here setting_select is a helper which is defined like this:
def setting_select(setting, choices, options={})
if blank_text = options.delete(:blank)
choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices
end
setting_label(setting, options).html_safe +
select_tag("settings[#{setting}]",
options_for_select(choices, Setting.send(setting).to_s),
options).html_safe
end
options_for_select allows you to pre-select an option by passing its value. Example:
<%= options_for_select([['Lisbon', 1], ['Madrid', 2], ...], 2) %>
output:
<option value="1">Lisbon</option>
<option value="2" selected="selected">Madrid</option>
More information about select tag and options_for_select.

Custom select options html attributes

I have an "add new product page" and I have a field in the database table "jos_stockmovement", "start_week" which contains data for the year and week.
In my "Add New Product" page I have a field dropdown-list named "Start Week" which holds the year and week, for example, "2012/36".
I want to make it so past weeks can be viewed but only the current week can be selected.
Here's my code:
<td colspan="99">
<%= fld.select :start_week, options_for_select(
StockMovement.order("year DESC, week DESC").map { | val |
[ "#{ val.year }/#{ val.week }", val.id ]
},
:selected => #product.start_week
),
:class => "ddl_SW"
%>
</td>
What you want to do is to add the disabled attribute to the past week options, like
<select name="post[stock_movement]">
<option value="1">Present</option>
<option value="2" disabled="disabled">Past</option>
<option value="3" disabled="disabled">Past</option>
</select>
You can do this in Rails3 (I don't think you can in Rails2) by using options_for_select as you were trying to.
stock_movement.rb
# not sure about the scope, maybe need to put in a lambda ?
scope :option_tags, order("year DESC, week DESC").map(&:option_tag)
def before_now?
# your test to know if the thing is before today or not
end
def option_tag
["#{ stock_movement.year }/#{ stock_movement.week }",
val.id,
before_now? ? {:disabled => :disabled} : {}]
end
your_view.rb
<td colspan="99">
<%= fld.select :start_week,
options_for_select(StockMovement.option_tags,
:selected => #product.start_week),
:class => "ddl_SW" -%>
</td>
How about that? I could not test it but should be ok.

Resources