Easy Form Drop-Downs With Collection_Select


It’s a pretty common thing in Ruby on Rails–or even in web development–that you have some set of objects that you want to list in a drop-down. Writing this code in raw HTML is tedious–you need to have a select tag, and multiple option tags in it.

First, let’s review some sample HTML code to help clarify. Say you have a list of customers, each with an ID and a name, and you want to list that. Each sales_agent has one client–a customer instance. The HTML code would look something like this:

<select name="sales_agent[customer_id]" id="sales_agent_customer_id">
<option value="1">Jack Straw</option>
<option value="6">Ahmed Haqq</option>
<option value="13">Dima Petriovich</option>
</select>

Notice the name and ID for the select tag, as per the Ruby on Rails conventions for mapping model objects. Option tags have a value and a display string.

So how can we do this more easily in Ruby on Rails?

Fortunately, for models, Ruby on Rails has a simple and convenient helper-method to help you do this quicker–collection_select. The API is:

collection_select("object_name", "field_name", list_of_objects, "value_field", "display_field")

For the above code, our API call might be something like this:

collection_select("sales_agent", "customer_id", @customers, "id", "name")

Assuming you had a customer model with an ID attribute and a name attribute, this would produce exactly the above code. So looking at the values we pass into the collection_select call:

  • The first parameter is the model that contains one element from the collection (eg. sales_agent)
  • Next is the field name in the model that refers to the collection element it contains (eg. customer_id)
  • Next is the variable containing the collection of items that we want to list (eg. @customers)
  • Next is the value attribute of the option tag (eg. the customer id)
  • Next is the display attribute of the option tag (eg. the customer name)

One final note: When you use this–in your views–you’ll need to select the collection first in your controller. Most likely you’ll use something like @customers = Customer.find(:all, :conditions => "owner_id = 3") or something similar to fetch the collection you want to display.

And that’s it! Tedious HTML selection fields become as simple as one collections_select call–providing you follow all the Rails conventions, and have models in your application domain.

Tags: ,     Posted in Development

Rate this article:
1 Star2 Stars3 Stars4 Stars5 Stars (7 votes, average: 3.14 out of 5)
Loading ... Loading ...

Related Content


8 Responses to “Easy Form Drop-Downs With Collection_Select”

  1. Justin Says:

    Okay, great, but this doesn’t explain at all how to use it. How do you get the selected option when you are in the controller? Rails documentation is significantly lacking in every aspect.

  2. ashes999 Says:

    @Justin: If you look at the original HTML, you’ll see: name=”sales_agent[customer_id]“. The Rails code generates equivalent HTML; it already follows the convention Rails knows, so it should automatically populate sales_agent[customer_id].

  3. Lex Says:

    The current signature is the following:

    collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})

    Sample usage (selecting the associated Author for an instance of Post, @post):

    collection_select(:post, :author_id, Author.find(:all), :id, :name_with_initial, {:prompt => true})

    Thanks for the article.

  4. Bryan Says:

    On this helper, what would be the best way to select a default?

    example
    searcher.get_approver}) %>

    This throws an error
    Syntax error, unexpected ‘{’, expecting ‘)’
    … @approvers, :id, :full_name {:selected => searcher.get_appr…

    I would also like an option for : “Create New Approver” which links to Approver.new

    Any ideas would be appreciated.

    On a secondary question;
    I have on the same form, a set of radio-buttons. I would like the toggle to enable or disable this collection_select control

    Thanks

  5. Bryan Says:

    searcher.get_approver}) %>

  6. Trung Says:

    Hi,

    I have a question:

    What if “display_field” is a virtual attribute which contains parameters?

    In your example, assume that to calculate the “name” attribute, we need to pass a parameter “language”. So how can we use the collection_select in this case?

    Thank you in advance.

  7. ashes999 Says:

    @Brian: sorry, no clue
    @Trung: I’m not sure. I assume if you put a function name, Rails will call the function and use the return value as the attribute. Why not try it, and let me know how it works out?

  8. Trung Says:

    @ashes999: Thanks for your reply. I have tried with collection_select but no progress. So I have found another solution by using select. For examples:

    select(”sales_agent”, “customer_id”, @customers.collect{|customer| [customer.name(params), id]})

    With this, you can call any instance function with params.
    Hope this help for somebody.

    @Bryan: Have you tried to put “,” before {:selected => …} in your code?

    Thanks and regards.

Leave a Reply