155

I am going through the Rails API docs for collection_select and they are god-awful.

The heading is this:

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

And this is the only sample code they give:

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

Can someone explain, using a simple association (say a User has_many Plans, and a Plan belongs to a User), what I want to use in the syntax and why?

Edit 1: Also, it would be awesome if you explained how it works inside a form_helper or a regular form. Imagine you are explaining this to a web developer that understands web development, but is 'relatively new' to Rails. How would you explain it?

hopper
  • 13,060
  • 7
  • 49
  • 53
marcamillion
  • 32,933
  • 55
  • 189
  • 380
  • 52
    Yes. That is the most awful documentation I have ever seen – Jaseem Nov 17 '12 at 19:01
  • 1
    To be fair, the documentation is quite ok, just not in the `FormBuilder` but in the `FormOptionsHelper`: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select – amiuhle Jul 27 '15 at 15:17
  • 2
    My favorite part is when you use collection_select in a form and that changes the whole signature so that the object is not part of the parameter list but instead collection_select is called as a method on the object. Don't think they mention that in the docs... – user3670743 Sep 23 '15 at 01:55
  • 3
    This is an open source project: if the documentation is poor, we have only ourselves to blame; it could be amazing if only we would do our bit to make it better. Small/simple PRs go a long way. – BenKoshy Feb 18 '20 at 23:21

2 Answers2

325
collection_select(
    :post, # field namespace 
    :author_id, # field name
    # result of these two params will be: <select name="post[author_id]">...

    # then you should specify some collection or array of rows.
    # It can be Author.where(..).order(..) or something like that. 
    # In your example it is:
    Author.all, 

    # then you should specify methods for generating options
    :id, # this is name of method that will be called for every row, result will be set as key
    :name_with_initial, # this is name of method that will be called for every row, result will be set as value

    # as a result, every option will be generated by the following rule: 
    # <option value=#{author.id}>#{author.name_with_initial}</option>
    # 'author' is an element in the collection or array

    :prompt => true # then you can specify some params. You can find them in the docs.
)

Or your example can be represented as the following code:

<select name="post[author_id]">
    <% Author.all.each do |author| %>
        <option value="<%= author.id %>"><%= author.name_with_initial %></option>
    <% end %>
</select>

This isn't documented in the FormBuilder, but in the FormOptionsHelper

amiuhle
  • 2,673
  • 1
  • 19
  • 28
alexkv
  • 5,144
  • 2
  • 21
  • 18
  • 41
    This is easily, one of the best explanations of a complex Rails structure I have seen. You used clear language, along with basic Rails constructs to solidify it. Thanks much!! – marcamillion Jan 19 '12 at 08:32
  • 2
    Why would you ever name it "post[author_id]" ? – Jaseem Nov 17 '12 at 19:02
  • @alexkv thank you - would you be able to elaborate on the significance of the :post, # field namespace and :author_id, # field name parameters (the first two) - I do not understand their purpose in the scheme of things - can't they be omitted? – BenKoshy Jul 27 '16 at 23:16
  • 1
    The first param can indeed be nil. If you are making a object form it will be that object so that the select has the same namespacing as the rest of the form. If that isn't needed, leave 1st as nil. The 2nd is the name of the control, so if it's to update a field on an object (1st parameter) then the field name is the second parameter. If you are making some form for other uses, the 2nd parameter is whatever you want the form control to be named and id'd. Why use this with nil 1st? Probably because you want collection_select for the :prompt options. – elc Feb 17 '17 at 00:38
  • 1
    I should also note that you can get the same effect tacking a prompt parameter onto a select_tag that's using options_for_select, which would likely answer the same as a collection_select with a nil object. – elc Feb 17 '17 at 00:52
23

I've spent quite some time on the permutations of the select tags myself.

collection_select builds a select tag from a collection of objects. Keeping this in mind,

object : Name of the object. This is used to generate the name of the tag, and is used to generate the selected value. This can be an actual object, or a symbol - in the latter case, the instance variable of that name is looked for in the binding of the ActionController (that is, :post looks for an instance var called @post in your controller.)

method : Name of the method. This is used to generate the name of the tag.. In other words, the attribute of the object you are trying to get from the select

collection : The collection of objects

value_method : For each object in the collection, this method is used for value

text_method : For each object in the collection, this method is used for display text

Optional Parameters:

options : Options that you can pass. These are documented here, under the heading Options.

html_options : Whatever is passed here, is simply added to the generated html tag. If you want to supply a class, id, or any other attribute, it goes here.

Your association could be written as:

collection_select(:user, :plan_ids, Plan.all, :id, :name, {:prompt => true, :multiple=>true })

With regards to using form_for, again in very simple terms, for all tags that come within the form_for, eg. f.text_field, you dont need to supply the first (object) parameter. This is taken from the form_for syntax.

sameers
  • 4,855
  • 3
  • 35
  • 44
zsquare
  • 9,916
  • 6
  • 53
  • 87
  • 2
    Thanks for taking the time...the only issue though is, in all honesty, your explanation doesn't help clarify things in my head. You used a lot of the terms in the actual definition. I do appreciate you taking the time though - so for that, I up voted it. – marcamillion Jan 19 '12 at 08:33
  • 6
    For the reasons so clearly stated by marcamillion, I down voted it. – Jamie Apr 07 '13 at 03:16