This blog is part of our Rails 7 series.
In web applications, forms are one of the most essential interfaces for user input and it can be tedious to write and maintain form markups with many attributes. Rails provide Action View Form Helpers for generating form markup.
Using select helper we can easily create select boxes in HTML with one <option> element for each option to choose from.
For example, let's say we have a list of cities for the user to choose from.
1# app/views/address/new.html.erb 2<%= form.select :city, ["Pune", "Mumbai", "Delhi"] %>
Rails will generate the following markup.
1<select name="city" id="city"> 2 <option value="Pune">Pune</option> 3 <option value="Mumbai">Mumbai</option> 4 <option value="Delhi">Delhi</option> 5</select>
Previously for generating a select box for weekday select, we needed to write a custom helper. Rails did not have anything out of the box for the weekday selection.
However, Rails 7 has added weekday_options_for_select and weekday_select using which we can easily generate a dropdown field of selecting a weekday.
Before
In Rails 6.1 we can create a dropdown field for weekday as shown here.
1# app/views/users/new.html.erb 2<%= form_with(model: user) do |form| %> 3 <div class="field"> 4 <%= form.label :weekly_off %> 5 <%= form.select :weekly_off, I18n.t('date.day_names') %> 6 </div> 7<% end %>
Or we can do something like this.
1# app/views/users/new.html.erb 2<%= form_with(model: user) do |form| %> 3 <div class="field"> 4 <%= form.label :weekly_off %> 5 <%= form.select :weekly_off, I18n.t('date.day_names').map.with_index.to_h %> 6 </div> 7<% end %>
Then The generated markup looks like this.
1<select name="user[weekly_off]" id="user_weekly_off"> 2 <option value="Sunday">Sunday</option> 3 <option value="Monday">Monday</option> 4 <option value="Tuesday">Tuesday</option> 5 <option value="Wednesday">Wednesday</option> 6 <option value="Thursday">Thursday</option> 7 <option value="Friday">Friday</option> 8 <option value="Saturday">Saturday</option> 9</select>
Here is how it would look if we go with the second option.
1<select name="user[weekly_off]" id="user_weekly_off"> 2 <option value="0">Sunday</option> 3 <option value="1">Monday</option> 4 <option value="2">Tuesday</option> 5 <option value="3">Wednesday</option> 6 <option value="4">Thursday</option> 7 <option value="5">Friday</option> 8 <option value="6">Saturday</option> 9</select>
Rails 7 onwards
We can use the weekday_options_for_select or weekday_select helper for generating a dropdown field for selecting a weekday.
1# app/views/users/new.html.erb 2<%= form_with(model: user) do |form| %> 3 <div class="field"> 4 <%= form.label :weekly_off %> 5 <%= form.select :weekly_off, weekday_options_for_select("Monday", day_format: :abbr_day_names) %> 6 </div> 7<% end %>
Or we can do something like this.
1# app/views/users/new.html.erb 2<%= form_with(model: user) do |form| %> 3 <div class="field"> 4 <%= form.label :weekly_off %> 5 <%= form.weekday_select :weekly_off, { selected: "Monday", day_format: :abbr_day_names } %> 6 </div> 7<% end %>
Then The generated markup looks like this.
1<select name="user[weekly_off]" id="user_weekly_off"> 2 <option value="Sunday">Sunday</option> 3 <option selected="selected" value="Monday">Monday</option> 4 <option value="Tuesday">Tuesday</option> 5 <option value="Wednesday">Wednesday</option> 6 <option value="Thursday">Thursday</option> 7 <option value="Friday">Friday</option> 8 <option value="Saturday">Saturday</option> 9</select>
weekday_options_for_select accepts a few options and all of them have a default value.
selected defaults to nil and if we provide this argument the value passed will be used as the selected option.
1 <!-- weekday_options_for_select("Friday") --> 2<option value=\"Sunday\">Sunday</option>\n 3<option value=\"Monday\">Monday</option>\n 4<option value=\"Tuesday\">Tuesday</option>\n 5<option value=\"Wednesday\">Wednesday</option>\n 6<option value=\"Thursday\">Thursday</option>\n 7<option selected=\"selected\" value=\"Friday\">Friday</option>\n 8<option value=\"Saturday\">Saturday</option>"
index_as_value defaults to false and if true it will set the value of each option to the index of that day.
1<!-- weekday_options_for_select(index_as_value: true) --> 2<option value=\"0\">Sunday</option>\n 3<option value=\"1\">Monday</option>\n 4<option value=\"2\">Tuesday</option>\n 5<option value=\"3\">Wednesday</option>\n 6<option value=\"4\">Thursday</option>\n 7<option value=\"5\">Friday</option>\n 8<option value=\"6\">Saturday</option>"
day_format defaults to :day_names and passing this a different I18n key will use different formats for the option display names and their values.
1<!-- weekday_options_for_select(day_format: :abbr_day_names) --> 2<option value=\"Sun\">Sun</option>\n 3<option value=\"Mon\">Mon</option>\n 4<option value=\"Tue\">Tue</option>\n 5<option value=\"We\">Wedn</option>\n 6<option value=\"Thu\">Thu</option>\n 7<option value=\"Fri\">Fri</option>\n 8<option value=\"Sat\">Sat</option>"
Note that :abbr_day_names options are built into Rails but we can define your array.
Check out this pull request for more details.