Friday, 17 July 2009

Adding prompt to select_tag

Rails's select method is pretty advanced. You can pass in all sorts of funky options to format your selector nicely, including :include_blank => true and the related :prompt => 'Pick one or else!'

select_tag, however, seems to have fallen behind in the usefulness-stakes and implements neither of the above... even though it does an extremely similar thing.

So here's a quick-hack function you can drop into ApplicationHelper to implement that functionality for you.

  # override select_tag to allow the ":include_blank => true" and ":prompt => 'whatever'" options
  include ActionView::Helpers::FormTagHelper
  alias_method :orig_select_tag, :select_tag
  def select_tag(name, select_options, options = {}, html_options = {})
    # remove the options that select_tag doesn't currently recognise
    include_blank = options.has_key?(:include_blank) && options.delete(:include_blank)
    prompt = options.has_key?(:prompt) && options.delete(:prompt)
    # if we didn't pass either - continue on as before
    return orig_select_tag(name, select_options, options.merge(html_options)) unless include_blank || prompt

    # otherwise, add them in ourselves
    prompt_option  = "<option value=\"\">" # to make sure it shows up as nil
    prompt_option += (prompt ? prompt.to_s : "") + "</option>"
    new_select_options = prompt_option + select_options
    orig_select_tag(name, new_select_options, options.merge(html_options))


sam said...

This was helpful. There are a few obvious and minor problems; I thought I'd post a quick comment so others can avoid a few minutes of head scratching. The write up and comments suggest that the :include_blank option is added by this monkey patch; the patch in fact adds :allow_blank. Further, the :allow_blank option doesn't actually add a blank option, rather it adds a 'Please choose' option. You can easily remove that label to make it blank, and change 'allow_blank' to 'include_blank' if you like.


Taryn said...

Hi Sam, Quite right.
I think I'd originally thought it was "allow_blank" - then checked the 'select' syntax to find it was called "include_blank" and only partly updated the code to reflect this.

I've updated the code snippet to match that now so it's all called include_blank.

You're right about the include_blank also populating it with a default select option of "Please Choose" rather than an actual blank. *blush*
I allowed our own choice of default prompt to intrude into the example code. Also now fixed.

Thanks for pointing that out!


Anonymous said...

Rails 3 seems to escape the new_select_options array, so you need to mark it as html_safe thus:

orig_select_tag(name, new_select_options.html_safe, options.merge(html_options))


Taryn said...

Cool, thanks Anonymous :)

Anonymous said...

Awesome. I'm working on a project on 2.8 and was driving myself nuts until I realized I was reading the APIDoc for 3. Quickly found your snippet and it worked like a charm! Thanks much.

Taryn said...

You're welcome.

Hmm, It is getting a bit like that.
I wonder if I should go through all my old posts and intentionally tag them with "Rails 2.X"...

I know there's still a hell of a lot of people working with it. We now have plenty of "legacy" rails codebases out there.

manoj prabakar said...

Hi Taryn,
Really nice post :) It helped me alot
in my project. Thanks :)