Using the new `weekday_select` in Rails 7
Tags: rails, ruby, webdev
Published: 2021-09-22 18:45:00

In most of the Rails apps I've built over the years I've had to add my own helpers for a weekday select. Normally Rails is great at providing most of the helpers you could ever want, so this omission has always been a little surprising to me. At Within3 I recently had to work on this again, and another engineer on my team shared my surprise at the omission. So I thought it was time for a [Rails PR](https://github.com/rails/rails/pull/42979).

The bulk of this PR adds the `weekday_options_for_select` method but you'll still need to wrap that in a `select` tag so I also added a `weekday_select` tag to the form builder. Now there are a few ways to build your weekday select so let start with an overview of the `weekday_options_for_select` method.

`weekday_options_for_select` accepts a few arguments, all of which have a default, for you to customize your options:

- `selected` (defaults to `nil`) if you provide this argument the value passed will be used to mark that option as selected:
```ruby
weekday_options_for_select("Friday")
# => "<option value=\"Sunday\">Sunday</option>\n
# <option value=\"Monday\">Monday</option>\n
# <option value=\"Tuesday\">Tuesday</option>\n
# <option value=\"Wednesday\">Wednesday</option>\n
# <option value=\"Thursday\">Thursday</option>\n
# <option selected=\"selected\" value=\"Friday\">Friday</option>\n
# <option value=\"Saturday\">Saturday</option>"
```
- `index_as_value` (defaults to false) if true will set the value of each option to the index of that day
```ruby
weekday_options_for_select(index_as_value: true)
# => "<option value=\"0\">Sunday</option>\n
# <option value=\"1\">Monday</option>\n
# <option value=\"2\">Tuesday</option>\n
# <option value=\"3\">Wednesday</option>\n
# <option value=\"4\">Thursday</option>\n
# <option value=\"5\">Friday</option>\n
# <option value=\"6\">Saturday</option>"
```
**NOTE:** "Sunday" will always be 0 even if you start on a different day (more on that in a minute) to stay consistent. In Ruby, if you call `wday` on a `Date` "Sunday" will always return 0 and `I18n.translate("date.day_names")` will return an array where "Sunday" is the first item. So we keep the value of "Sunday" 0 regardless of where it falls in the array.

- `day_format` (defaults to `:day_names`) passing this a different I18n key will use different formats for the option display names and values.
```ruby
weekday_options_for_select(day_format: :abbr_day_names)
# => "<option value=\"Sun\">Sun</option>\n
# <option value=\"Mon\">Mon</option>\n
# <option value=\"Tue\">Tue</option>\n
# <option value=\"We\">Wedn</option>\n
# <option value=\"Thu\">Thu</option>\n
# <option value=\"Fri\">Fri</option>\n
# <option value=\"Sat\">Sat</option>"
```
**NOTE:** `:abbr_day_names` is built into Rails but you could define your own Array and use that key if desired. Example:
```yml
en:
  date:
    alt_day_names: [Sun, Mon, Tues, Weds, Thurs, Fri, Sat]
```
```ruby
weekday_options_for_select(day_format: :alt_day_names)
# => "<option value=\"Sun\">Sun</option>\n
# <option value=\"Mon\">Mon</option>\n
# <option value=\"Tues\">Tues</option>\n
# <option value=\"Weds\">Weds</option>\n
# <option value=\"Thurs\">Thurs</option>\n
# <option value=\"Fri\">Fri</option>\n
# <option value=\"Sat\">Sat</option>"
```
- **Bonus Option** I recently made [another PR](https://github.com/rails/rails/pull/43037) that adds a `beginning_of_week` option so you can specify which day the select starts on. This defaults to `Date.beginning_of_week` so as long as you have that set you're good to go, if you don't or you want to override it, here's how:
```ruby
Date.beginning_of_week
# => :sunday
weekday_options_for_select(beginning_of_week: :monday)
# => "<option value=\"Monday\">Monday</option>\n
# <option value=\"Tuesday\">Tuesday</option>\n
# <option value=\"Wednesday\">Wednesday</option>\n
# <option value=\"Thursday\">Thursday</option>\n
# <option value=\"Friday\">Friday</option>\n
# <option value=\"Saturday\">Saturday</option>\n
# <option value=\"Sunday\">Sunday</option>"
```

Like I said you'll still need to wrap `weekday_options_for_select` in a `select` tag so I also added a `weekday_select` tag to the form builder. Lets take a look at how to use that.

Lets say we have a newsletter that we send our to our users and we want our users to be able to set what day they receive that newsletter. We can add a `newsletter_send_day` column to our User and then update the form to look a little something like this:
```erb
<%= form_with model: @user do |form| %>
  <%= form.label :newsletter_send_day %>
  <%= form.weekday_select :newsletter_send_day %>
<% end %>
```
And that's it!

You'll get something that looks like this in your form:
```html
<select name="user[newsletter_send_day]" id="user_newsletter_send_day">
  <option value="Sunday">Sunday</option>
  <option value="Monday">Monday</option>
  <option value="Tuesday">Tuesday</option>
  <option value="Wednesday">Wednesday</option>
  <option value="Thursday">Thursday</option>
  <option value="Friday">Friday</option>
  <option value="Saturday">Saturday</option>
</select>
```
You can use any combination of the `weekday_options_for_select` arguments to modify your selects options.

You can try `weekday_select` and `weekday_options_for_select` for yourself in Rails 7, which at the time of this writing is in an alpha prerelease.  Let me know what you think about these new form options and if you get a chance to use them in any of your projects!