I have programmed using rails for a while, but while helping with a Stackoverflow question i realized I didn’t have a very firm grasp of the interworkings of select_tag or options_for_select. So I wrote this blog post in order to get a better understanding of it.
Both of these tags are located in ActionView::Helpers and are used to turn some collection of stuff into an intelligently grouped options list that can be selected.
Rails provides several ways to do this ranging from simple to intimidating (meaning, you pass in 5 different options to a method and hope that the order is correct). The latter can be a little daunting for beginner developers and frustrating for more advanced developers who use the components only often enough to forget the order before the next time they use them.
To start with, let’s create a simple select box in html.
[ruby] <select name="user_id" id="user_id"> </select> [/ruby]
This html is the minimum you can generate with a select_tag call, you must supply either a name or symbol that is converted using ruby into the name=” and id=” above. The above select tag would look like this.
[ruby] <%= select_tag(:user_id) %> [/ruby]
Note that you cannot just call select_tag with no options. The element for the name/id is required.
Now that we have a select box that will submit a user_id in the form, we will want to put some options in the box. A quick and dirty way to accomplish this task is to add a string representing the options.
[ruby] <%= select_tag(:user_id, '<option value="1">Jemmy Legs</option><option value="2">Talos</option>') %> [/ruby]
However, this string will not work. If you put this in a rails project it will display an empty dropdown box because select_tag is actually a facade for content_tag. The options in the second argument are passed to a call to content_tag in the helper. Content tag sends this to another helper which passes your content options to ERB::Util.unwrapped_html_escape.
So ultimately, it is escaped in a way where it is ‘safer’ before it leaves the server
To get it to work you can chain on the html_safe method method.
[ruby] <%= select_tag(:user_id, '<option value="1">Jemmy Legs</option><option value="2">Talos</option>'.html_safe) %> [/ruby]
Now that we are creating getting a dropdown box, we will want an easier way to build the options. This can be accomplished using the method options_for_select to generate our options AND set them as html_safe without having to type out all the html.
The options_for_select arguments is a set of name and value pair represented by a hash, array, enumerable, or some other type. Below is a nested array demonstrating their format.
[
[‘textdisplayed in dropdown box’, ‘value_sent_to_server’],
[‘Jemmy Legs’, 1],
[‘Talos’, 2]
]
In action it looks like this
[ruby] #just the options <%= options_for_select([['Jemmy Legs', 1], ['Talos', 2]])%> #combined together with select tag <%= select_tag(:user_id, options_for_select([['Jemmy Legs', 1], ['Talos', 2]]))%> [/ruby]
Options_for_select is located in ActionView::Helpers::FormOptionsHelper. If the object passed to it (the nested array, hash, etc) responds to .map and provides a text and value through option_text_and_value, then it calls the content_tag_string helper on each text-value pair, joins them with a new line and finally calls html_safe on the results.
My next blog I plan to dive deeper in the helpers mentioned above. Here are some good links in the meantime.
Good Links
Source
https://github.com/rails/rails/blob/7e375afba30951b60a3e606ccbfe3f28b0df5e1a/actionview/lib/action_view/helpers/form_tag_helper.rb
Rails Guides
http://guides.rubyonrails.org/form_helpers.html#making-select-boxes-with-ease
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html
facade pattern
http://en.wikipedia.org/wiki/Facade_pattern
That was very helpfull. Thanks! Had a hard time finding some explaining of the select_tag
cheers
Nice write up, easy to understand.
Thank you 🙂 Because of your message i may finally get to writing up part two of this thing, haha.
A sorely needed explanation. Thank you!