Ruby on Rails – Disabling a select tag using the select helper

There is a bit of a subtlety to this, and it took me a while to figure this out. If I used the select_tag helper I was able to disable the select menu, but using comparable code with the select helper it wouldn’t be disabled.

<% options= ['one', 'two', 'three', 'four'] %>
 
<%= select_tag :content, options_for_select(options), :disabled => true %><br />
<%= f.select :content, options, :disabled => true %>

Here my select_tag would be disabled like I wanted, but the f.select would not be. This made me quite perplexed, and with more research I discovered it’s because the “disabled” option for the select helper has been mapped to allow the developer to disable specific elements. For example, this code similarly yields differing behavior:

<% options= ['one', 'two', 'three', 'four'] %>
<% disabled_options= ['two', 'four'] %>
 
<%= select_tag :content, options_for_select(options), :disabled => disabled_options %><br />
<%= f.select :content, options, :disabled => disabled_options %>

In the case of the select_tag helper, the menu is still disabled as the disabled_options array will evaluate to true. For the select helper, however, the disabled_options array will tell the helper to set the options that match elements of the array to disabled. This is where I remained stuck for a while, not being able to figure out a way to use the select helper to disable the menu. Then looking more closely at the API documentation, I noticed a difference between the two helpers.

select_tag(name, option_tags = nil, options = {})

select(object, method, choices, options = {}, html_options = {})

The select helper has an additional set of parameters called “html_options” after the options. The select_tag helper conversely simply uses any parameters in its options array that don’t match expected options as html attributes. Based on this I wondered if I passed a hash array for the options parameter, if I could explicitly pass disabled as an html option, as follows:

<% options= ['one', 'two', 'three', 'four'] %>
 
<%= select_tag :content, options_for_select(options), :disabled =>true %><br />
<%= f.select :content, options, {}, :disabled => true %>

Sure enough this worked, and gave me the same behavior for both helpers! I was quite surprised to find such inconsistent behavior for these two helpers. It was reminiscent of my experiences with PHP and I’m disappointed to see it here in the Rails API. I would be curious to hear an explanation for why these two helpers are so different.

Happy Coding!

Tagged , , , , , , , , ,
  • michelegera

    Thanks!I keep banging my head against this, and I forgot the syntax every time.Bookmarked for future reference!

  • B Seven

    Thanks! It helped me a lot and it is very easy to understand.

  • Aleksandar

    “It was reminiscent of my experiences with PHP and I’m disappointed to see it here in the Rails API”!?
    I am in rails more than a year, but as you find more stupid things than
    in PHP. From my experiences PHP is much better to write complex things
    than RoR.

    And add to these naming convention (plural/singular), problem with multiple nested forms (add/remove) etc…

    regards

  • Ryan Jackson

    Is there a way to make the disabled option the default?

    • Anonymous

      Hey Ryan,
      As far as I know there’s no way to set a default configuration for the helpers. Usually what I’ll do is define an instance variable with the values I want, and then use them in each helper (you can use a merge to override those if you need an option different for a specific case). That at least gives me a centralized place where I can change the options if I want to.

      Cheers,
      Ben

      • Ryan Jackson

        Ben,
        Thanks for your response! I don’t think that’s what I’m trying to do, though it does sound useful.

        After looking further into this, I think the ‘:prompt’ option is the most semantic for what I’m trying to accomplish.

  • Jesse Crockett

    Thanks for this. I couldn’t get the thing to disable without this tricky bit: true %>