This is a documentation once and for all on how to render a select tag in rails view with a disabled option that is preselected.
I find myself having to refer to stackoverflow often for the solution because it just isn’t intuitive. It requires some sort hacking before it can be rendered the way I needed it. Often, I would not understand the purpose of writing the code that way unless I can remember the purpose and see the end goal of what it is trying to achieve.
Code that is not self-explanatory is a sign of code smell. That is so not Rails.
The Old Way Of Coding
The way I used to code out the list of options is to create an array that contains yet another array as shown above. In the inner array, the first value will be the label that users will see when selecting the option from the list, while the second value is the actual value to be passed to the backend.
Here is the part that raises question. In line 3, I prepend the array of users using the
+ operator with an array containing
Please select user. This is meant to be the first value to be selected so that it can act as a prompt for the select tag.
I use the
options_for_select helper to make it a little easier to set the with the
disabled options. The
selected key will select the prepended array’s value as the default value for the select tag, and the
disabled key will set it as disabled so that users cannot choose it and send an invalid value to the backend.
Hence, without knowing the end goal, the code from line 3 to 5 will raise eyebrows. There has to be a better way and indeed there is. But first, let me touch on the remaining lines for completion sake.
Line 7 is for other options for the Rails
select helper, like
include_blank which we are not using.
Line 8 is for additional HTML attributes.
The New Way Of Coding
Rails 6 has added the
prompt helper in the Rails
select tag to achieve exactly this purpose. Let’s compare the new way of writing that snippet.
We are no longer using the
options_for_select helper as we do not need its
disabled options for any more unsettling hackery.
In its place, we use the
prompt key in the line 6 under the
options argument for the Rails
select helper to give achieve the same result.
disabled key here makes the prompt an unselectable option. Leave it out if your UX allow selection of
nil value. You may need to engage the
include_blank key here as well.
selected key sets the selected value conditionally to be the prompt’s unless the form object already has a
user_id value. This part is a little quirky; the concept of selecting the value of the form object should already be implemented by default without having to write out the conditional code as in line 4. I believe this is constructed to fit all scenarios for all UX requirements, but I can’t really be sure. I’ll check it out someday.
Note that by using prompt, the prompt will not be present as one of the options if the form object already has a value.
This is a lot neater and much more like the Rails we know. There is no more questionable code and every line and option has a clear purpose.