PullMonkey Blog

30 Mar

Dynamic Select Boxes - Ruby on Rails


UPDATE: There is a dynamic select boxes for rails 3 tutorial now, so if this isn't working for you, check it out.

I have seen this asked a lot in the forums, so I thought I would write up a little tutorial.

For this tutorial I am going to have three select boxes. The first select box will be a super category of the next two select boxes and the second select box will be a super category of the third select box. I hope that makes sense. To demonstrate, I thought I would use Genre -> Artist -> Song. So let's get started:

Create your models and build your migrations:

1
2
3
4

ruby script/generate model genre name:string
ruby script/generate model artist name:string genre_id:integer
ruby script/generate model song title:string artist_id:integer

Populate your genres, artists and songs through a migration:

1
2

ruby script/generate migration create_hierarchy

Contents of migration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

class CreateHierarchy < ActiveRecord::Migration
  def self.up
    g1 = Genre.create(:name => "Genre 1")
    g2 = Genre.create(:name => "Genre 2")
    g3 = Genre.create(:name => "Genre 3")

    a1 = Artist.create(:name => "Artist 1", :genre_id => g1.id)
    a2 = Artist.create(:name => "Artist 2", :genre_id => g1.id)
    a3 = Artist.create(:name => "Artist 3", :genre_id => g2.id)
    a4 = Artist.create(:name => "Artist 4", :genre_id => g2.id)
    a5 = Artist.create(:name => "Artist 5", :genre_id => g3.id)
    a6 = Artist.create(:name => "Artist 6", :genre_id => g3.id)

    Song.create(:title => "Song 1",  :artist_id => a1.id)
    Song.create(:title => "Song 2",  :artist_id => a1.id)
    Song.create(:title => "Song 3",  :artist_id => a2.id)
    Song.create(:title => "Song 4",  :artist_id => a2.id)
    Song.create(:title => "Song 5",  :artist_id => a3.id)
    Song.create(:title => "Song 6",  :artist_id => a3.id)
    Song.create(:title => "Song 7",  :artist_id => a4.id)
    Song.create(:title => "Song 8",  :artist_id => a4.id)
    Song.create(:title => "Song 9",  :artist_id => a5.id)
    Song.create(:title => "Song 10", :artist_id => a5.id)
    Song.create(:title => "Song 11", :artist_id => a6.id)
    Song.create(:title => "Song 12", :artist_id => a6.id)
  end

  def self.down
# you can fill this in if you want.
  end
end

Yes, I know it is generic data, sorry. So anyway, as you can see there are 3 genres, each with 2 artists, for a total of 6 artists each with 2 songs for a total of 12 songs. Each genre has 4 songs through its artists. Ok, so now we need to populate the database:

1
2

rake db:migrate

Now we need to modify our models to set up the associations.

1
2
3
4
5
6
7
8

class Genre < ActiveRecord::Base
  has_many :artists
  has_many :songs, :through => :artists
end
class Artist < ActiveRecord::Base
  has_many :songs
end

That should be it, now let's go to the console and see that all this works:

1
2
3
4
5
6
7
8
9
10

ruby script/console 
Loading development environment (Rails 2.0.2)
>> g = Genre.find(:first)
=> #<Genre id: 1, name: "Genre 1", created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">
>> g.artists
=> [#<Artist id: 1, name: "Artist 1", genre_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Artist id: 2, name: "Artist 2", genre_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">]
>> g.songs
=> [#<Song id: 1, title: "Song 1", artist_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Song id: 2, title: "Song 2", artist_id: 1, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Song id: 3, title: "Song 3", artist_id: 2, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">, #<Song id: 4, title: "Song 4", artist_id: 2, created_at: "2008-03-30 11:52:25", updated_at: "2008-03-30 11:52:25">]
>> 

Looks like it works :) Ok, now on to the controller. Our controller needs to have some action for the view, I just used index, and two other actions, for remote function calls, I called these update_artists and update_songs. update_artists() is called when a genre is changed and it updates the list of artists and the list of songs based on the genre. update_songs() only updates the songs based on the artist. So let's look at this code:

# the controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

class TestItController < ApplicationController
  def index
    @genres  = Genre.find(:all)
    @artists = Artist.find(:all)
    @songs   = Song.find(:all)
  end

  def update_artists
    # updates artists and songs based on genre selected
    genre = Genre.find(params[:genre_id])
    artists = genre.artists
    songs   = genre.songs

    render :update do |page|
      page.replace_html 'artists', :partial => 'artists', :object => artists
      page.replace_html 'songs',   :partial => 'songs',   :object => songs
    end
  end

  def update_songs
    # updates songs based on artist selected
    artist = Artist.find(params[:artist_id])
    songs  = artist.songs

    render :update do |page|
      page.replace_html 'songs', :partial => 'songs', :object => songs
    end
  end
end

Now as far as views go we have one view (index.html.erb) and two partials (_songs and _artists). Let's take a look at those:

# the _songs partial (_songs.html.erb):

1
2
3

<%= collection_select(nil, :song_id, songs, :id, :title,
                     {:prompt   => "Select a Song"}) %>

# the _artists partial (_artists.html.erb):

1
2
3
4
5
6

<%= collection_select(nil, :artist_id, artists, :id, :name,
                     {:prompt   => "Select an Artist"},
                     {:onchange => "#{remote_function(:url  => {:action => "update_songs"},
                                                      :with => "'artist_id='+value")}"}) %>
<br/>

# and last, but not least, the index view (index.html.erb):

1
2
3
4
5
6
7
8
9

<%= javascript_include_tag :defaults %>
<%= collection_select(nil, :genre_id,  @genres,  :id, :name,
                      {:prompt   => "Select a Genre"},
                      {:onchange => "#{remote_function(:url  => {:action => "update_artists"},
                                                       :with => "'genre_id='+value")}"}) %>
<br/>
<div id="artists"><%= render :partial => 'artists', :object => @artists %></div>
<div id="songs"><%= render :partial => 'songs',   :object => @songs %></div>

Ok, this probably takes some explanation. I will save that for part II, where I will also improve upon what we have so far and include a demo.


For now, if you have any questions, just ask me in the comments.



106 Responses to “Dynamic Select Boxes - Ruby on Rails”

  1. By Adriano on Mar 30, 2008 | Reply

    Nice tutorial, I will be doing it, soon.
    Just a nice consideration does the render_html works in ie ?

  2. By charlie on Mar 30, 2008 | Reply

    @Adriano - do you mean the replace_html rjs line? IAE, it should work in IE, let me know if you run into any problems.

  3. By Jonathan on Mar 30, 2008 | Reply

    I’m kind a newbie in rails, shouldnt the controller be the app controller ?
    I created a folder named test in it i added files index.rhtml and the 2 partials in this folder and modified the app controller, am I doing something wrong ?
    I used to just use script generate/scaffold so I dont know which error it is. Thanks in advance ….

  4. By Adriano on Mar 30, 2008 | Reply

    Thanks for the tutorial! all the previous that I saw when using IE it would not work with replace html. This is the first fully working, fully explained tutorial about cascading select I ever saw (and i searched over 40). Congrats, and thanks for making me unstuck in this problem =D

  5. By charlie on Mar 30, 2008 | Reply

    @Adriano - glad it worked for you and thanks for the nice comments

    @Jonathan - sure you could use the app controller, if you mean app/controllers/app_controller.rb, and not app/controllers/application.rb. I just like using test_it for my controller for some reason.
    Here is a very basic guide:
    (assuming you did the database and models)
    1) ruby script/generate controller <whatever you want>
    2) copy the code (excluding the class (top) and end(bottom)) from what I have in my controller code to your app/controllers/<whatever_you_called_it>.rb
    3) copy the code from index.html.erb to app/views/<whatever you called it>/index.html.erb
    4) do step 3 for both partials
    5) start your server and go to http(s)://<your domain>/<whatever you called your controller>

    That ought to get you close at least.

  6. By bonhoffer on Mar 30, 2008 | Reply

    this is truly great. thanks for your simple, clean tutorial.

  7. By cworth on Mar 30, 2008 | Reply

    I can’t get this to work. Using the debugger, execution never gets to the update_artists function. Any advice?
    Thanks

  8. By cworth on Mar 30, 2008 | Reply

    Got it to work. Forgot a line of code.
    Works great!

  9. By cworth on Mar 30, 2008 | Reply

    Any idea on how to get this to work with new or edit forms? I get null values saved in the genre_id and artist_id fields whenever I try to create a new song or edit a song. Thanks

  10. By charlie on Mar 30, 2008 | Reply

    @cworth -
    When you create a new song, you only have to associate the artist_id. When you submit a new song, what params do you have as a result?

  11. By maige on Mar 30, 2008 | Reply

    This is a clear and straight forward example. Thanks!

  12. By enduddyangedy on Mar 30, 2008 | Reply

    select(personal) locality. So to out!

  13. By ganez on Mar 30, 2008 | Reply

    I can’t get this to work. Execution never gets to the update_artists function. ???

  14. By Andy on Mar 30, 2008 | Reply

    Thanks for the article, it was really clear and easy to follow.

    Is there any way that the artist drop-down is only populated once a genre has been selected, and the song drop-down is only populated once the artist has been selected? Ideally the unpopulated drop-downs would be disabled until they’re populated.

  15. By ganez on Mar 30, 2008 | Reply

    i cant able to select artist values as well as song value in dropdown….any suggestions pls..

  16. By charlie on Mar 30, 2008 | Reply

    @Andy - Just remove this line from update_artists:
    page.replace_html ’songs’, :partial => ’songs’, :object => songs
    You can start with the drop-downs disabled then in the render :update, you can use rjs to enable the appropriate one

    @ganez - Did you populate your database? I will probably need more information.

  17. By Geoff on Mar 30, 2008 | Reply

    Cool tutorial. How would u change this so that an Artist could be in two different Genre’s. Say you wanted to be able to find the one entry for Shakira in both the "Spanish" Genre and the "Pop" Genre. Thanks!

  18. By charlie on Mar 30, 2008 | Reply

    @Geoff - you would need a join table between genres and artists, such that artist.genres is possible. Then a few other changes … I just created an example for you - http://pullmonkey.com/2008/8/5/dynamic-select-boxes-many-to-many-ruby-on-rails

  19. By Harish Kumar on Mar 30, 2008 | Reply

    Hi
    its is very nice example u have explain here and i implemneted also its working fine. I modified the application little like i added one button and when i click on this button i need the value selected like the genre id, artist Name and song name and display this value in controller action for other operation but i unable to get i tried a lot
    can u help ………..

    Thanks in Advance
    Harish

  20. By charlie on Mar 30, 2008 | Reply

    @Harish - You can just wrap the whole thing in a form and add a submit button. Then you use params inside your action to get your values.

  21. By boblu on Mar 30, 2008 | Reply

    Thanks for this great tutorial.
    I implement your method to my application.
    Everything works all right in Firefox and Opera.
    However, I cannot get it working in IE7.
    The only difference between mine and yours is the the render target tag. You used <div id="artists"></div>. And I used <span id="artists"></span>
    But I do not think this is the reason why it cannot work in IE7.
    Do you have some ideas?

  22. By charlie on Mar 30, 2008 | Reply

    @boblu - seems that some of your comment did not register. Use this information to post html/ruby code in your comment - http://pullmonkey.com/2008/7/23/open-flash-chart-ii-plugin-for-ruby-on-rails-ofc2#comment-46303

  23. By Drew on Mar 30, 2008 | Reply

    I am having a problem translating this box into a create / edit form_for. I’ve simplified it and adapted to my application. So I have sections, each section has many categories. When I create an article, I use one form_for that renders a partial for the form. Within that partial, I render another partial for the categories depending on which section is chosen (like the genre / artist relationship). When I submit the form, there is not a parameter for the category_id in the param list.

    My form code is below

    new.html.erb
    <filter:code attributes=lang="ruby">
    <% form_for :post, :url => {:action => ‘create’}, :html => { :multipart => true } do |f| %>
    <%= render :partial => ‘form’, :locals => { :f => f } %>
    <%= submit_tag ("Create", :action => ‘create’, :style => "margin: 1.5em 0 0 100px;") %>
    <% end %>
    < /filter:code>

    _form partial
    <filter:code attributes=lang="ruby">
    <table>
    <tr>
    <th>Title</th>
    <td><%= f.text_field ( :title, :size => 40, :style => "font-size: 1.0em;") %></td>

    </tr>
    <tr>
    <th>Section</th>
    <td><%= collection_select(nil, :section_id, @sections, :id, :name,
    {:prompt => "Select a section"},
    {:onchange => "#{remote_function(:url => {:action => "update_categories"},
    :with => "’section_id=’+value")}"}) %></td>
    </tr>
    <tr>
    <th>Category</th>
    <td><div id="categories"><%= render :partial => ‘categories_list’, :object => @categories %></div>
    </td>
    </tr>
    </table>
    < /filter:code>

    _categories_list partial
    <filter:code attributes=lang="ruby">
    <%= collection_select(nil, :category_id, @categories, :id, :name,
    {:prompt => "Select a category"}) %>
    < /filter:code>

  24. By charlie on Mar 30, 2008 | Reply

    @Drew - you left the space in there < /filter:code> :)
    Anyway, post the html page source, so I can look at what this code is generating.

  25. By Vinay on Mar 30, 2008 | Reply

    Thanks for an awesome tutorial! :) Simple and effective. I am trying to do this for a nested resource Company which is nested under Users. Once the Company is selected, a Contacts drop down is to be populated. And my update_contacts method is in the Companies Controller. The generated path for this is update_contacts_company_path and i need to pass the session[:user_id] along with this. I dont know how to construct the URL for this. The company_id is getting sent in the :with param whereas the url can be generated only if it sent alongwith the path like this - update_contacts_company_path(session[:user_id], company_id). Can someone help me out with fixing this?

  26. By charlie on Mar 30, 2008 | Reply

    @Vinay - Thanks. I can’t really tell what you are asking for without an example. Are you talking about this line:<filter:code attributes=lang="ruby"><%= collection_select(nil, :genre_id, @genres, :id, :name,
    {:prompt => "Select a Genre"},
    {:onchange => "#{remote_function(:url => {:action => "update_artists"},
    :with => "’genre_id=’+value")}"}) %></filter:code>And you want to use a nested named route and get the session[:user_id] passed in as user_id, try this:<filter:code attributes=lang="ruby">{:onchange => "#{remote_function(:url => update_contacts_company_path,
    :with => "’genre_id=’+value&user_id=#{session[:user_id]}}")}"}) %></filter:code>Let me know.

  27. By charlie on Mar 30, 2008 | Reply

    I messed up the quotes on the :with string:<filter:code attributes=lang="ruby">"#{remote_function(:url => update_contacts_company_path, :with => "’genre_id=’+value+’&user_id=#{session[:user_id]}’")}"}) %></filter:code>

  28. By Vinay on Mar 30, 2008 | Reply

    Thanks Charlie! I cant try this until tonight though. So will let you know asap :). I was trying to pass the session[:user_id] in the :with hash(is it a hash?) and was not sure of the correct syntax. Will try this and let you know soon. Thanks again!

  29. By charlie on Mar 30, 2008 | Reply

    @Vinay - :with is a string. it is used like you would construct a GET url when passing variables.

    So, http://pullmonkey.com?var1=&lt;somevalue&gt;&var2=&lt;…&gt;&... is the same as :url => "pullmonkey.com", :with => "var1=<somevalue>&var2=<…>&…"

  30. By Vinay on Mar 30, 2008 | Reply

    @Charlie - Thanks for that gyaan(explanation) :). I changed it the way you have showed. The Ajax call does not seem to be running though. I have the Javacript files included. Also, this line is causing an error in the contacts partial.
    <%= collection_select(nil, :contact_id, contacts, :id, :name,{:prompt => "Select Contact"}) %>
    Here, ‘contacts’ is a nil object and so Rails tries to do nil.map which does not exist. How did you work around this?

  31. By Mayo on Mar 30, 2008 | Reply

    Hi there,

    trying this I never get above the first steps with migratin the joined table. As much as I tried to find any mistake I allways get:

    == 20080927160238 CreateHierarchy: migrating ==================================
    rake aborted!
    undefined method `artist_id=’ for #<Song:0×31e77f8>

    Any idea?

  32. By charlie on Mar 30, 2008 | Reply

    @Mayo - Make sure you typed this line correctly:
    ruby script/generate model song title:string artist_id:integer

    Also, post your RAILS_ROOT/db/migrate/…songs.rb migration file

  33. By Ernest on Mar 30, 2008 | Reply

    Thanks. Your tutorial is clear and effective. I’m trying to use this technique to have one select for states and other for cities for a person database. However, when I change the state, I get an error:

    `@person[address_attributes]‘ is not allowed as an instance variable name

    The partial for cities is:

    <filter:code attributes=lang="ruby">

    <% fields_for "person[address_attributes]", address do |f| %>

    <%= f.collection_select(:city_id, cities, :id, :nombre,
    {:prompt => "City"}) %>

    <%end%>

    </filter:code>

    Each person has_one address. I hope you can shed some light here. :-)

  34. By charlie on Mar 30, 2008 | Reply

    @Ernest - Glad you like this tutorial.

    It wouldn’t surprise me if you had to do something like this:<filter:code attributes=lang="ruby"><% fields_for "person[address_attributes][]", address do |f| %></filter:code>This way the hash of attributes can be populated … as in an address has a street which would be at person[address_attributes][street] and city at person[address_attributes][city].

    Give it a shot. Let me know.

  35. By Marcus on Mar 30, 2008 | Reply

    Hey Charlie,

    This is a great tutorial. I was able to make it work on the song/artist/genre scenario but when I applied to my image gallery scenario it did not work

    basicaly I have:

    images
    galleries
    subcats

    an the relationships are:

    images belong_to subcats
    images belong_to galleries
    subcats belong_to galleries
    subcats has_many images
    galleries has_many images, through :subcats

    so on image edit and new views I’m trying to create a dynamic select for galleries which will populate subcats.
    Image table has gallery_id and subcat_id.

    and here is how I used your tutorial:

    edit.html.erb
    <filter:code attributes=lang="ruby">
    <p>
    <label for="gallery">Gallery:</label>
    <%= collection_select(nil, :gallery_id, @galleries, :id, :title,
    {:prompt => "Select a Gallery"},
    {:onchange => "#{remote_function(:url => {:action => "update_subcats"},
    :with => "’gallery_id=’+value")}"}) %>
    <div id="subcats">
    <label for="subgallery">Sub Gallery:</label>
    <%= render :partial => ’subcats’, :object => @subcats %>
    </div>
    </p>
    </filter:code>

    images_controller.rb
    <filter:code attributes=lang="ruby">
    def new
    @image = Image.new
    @galleries = Gallery.find(:all)
    @subcats = Subcat.find(:all)
    respond_to do |format|
    format.html # new.html.erb
    format.xml { render :xml => @image }
    end
    end

    # GET /images/1/edit
    def edit
    @image = Image.find(params[:id])
    @galleries = Gallery.find(:all)
    @subcats = Subcat.find(:all)
    end

    def update_subcats
    # updates artists and songs based on genre selected
    gallery = Gallery.find(params[:gallery_id])
    subcats = genre.subcats

    render :update do |page|
    page.replace_html ’subcats’, :partial => ’subcats’, :object => subcats
    end
    end
    </filter:code>

    _subcats.html.erb - is the only partial I created since I’m using gallery populate subcat.
    <filter:code attributes=lang="ruby">
    <%= collection_select(nil, :subcat_id, subcats, :id, :title,
    {:prompt => "Select an Sub Gallery"}
    ) %>
    <br/>
    < /filter:code>

    both dropdowns are showing and the second one does no respond to the first one.

    Prototype is there.

    Am I missing anything???

  36. By charlie on Mar 30, 2008 | Reply

    @Marcus - You have one tiny typo in your update_subcats action.

    subcats = genre.subcats
    should be
    subcats = gallery.subcats # using gallery.

    Your update_subcats() action is only called in a remote_function, so you won’t see the error or even maybe know there is an error unless you look in the log (development.log or production.log depending on the env). I am sure your log must have an undefined method subcasts for nil error or whatever.

    Let me know, if you still have problems.

  37. By Andrew on Mar 30, 2008 | Reply

    Great stuff. Really awesome write-up!

    Is there a way to reset the select the sub-selections if the user resets the main selection? For example, a user initially selects a genre (and the genre’s entries pop up), but then decides to reset the genre selection by clicking on "Select a Genre". Can we reset the song selection list to display all songs now (or even disable it until the user selects a genre)?

  38. By charlie on Mar 30, 2008 | Reply

    @Andrew -

    So if the user select "Select a Genre" again, we can display ALL Songs and ALL artists like this:
    1) either check the params[:genre_id] or check the resulting genre
    2) if the params[:genre_id] is 0 then we can return all the artists and songs
    if the genre is nil, we can return all the artists or songs
    Something like this might work (probably best to check the params[:genre_id] … should be 0) -
    <filter:code attributes=lang="ruby"> def update_artists
    # updates artists and songs based on genre selected
    # since we can have an invalid genre_id lets rescue it
    genre = Genre.find(params[:genre_id]) rescue nil
    # check the genre_id, if it is 0 then the user selected the prompt and we need to redisplay all artists and songs
    artists = params[:genre_id] == "0" ? Artist.all : genre.artists
    songs = params[:genre_id] == "0" ? Song.all : genre.songs

    # this part stays the same
    render :update do |page|
    page.replace_html ‘artists’, :partial => ‘artists’, :object => artists
    page.replace_html ’songs’, :partial => ’songs’, :object => songs
    end
    end</filter:code>

    ** Warning — not tested, so let me know how it goes

  39. By Frechdax75 on Mar 30, 2008 | Reply

    I have a problem to translate this into a create / edit form_for.
    When I create an user, I use one form_for that renders a partial for the form. Within that partial, I render another partial for the aps.
    When I submit the form, there is not a parameter for the ap_id in the controller.

    new/edit.html.erb

    <% form_for(@user) do |u| %>
      <%= render :partial => ‘form’, :locals => {:u => u} %>
      <p><%= u.submit "Anlegen" %></p>
    <% end %>

    _form.html.erb

    <%= collection_select(:user, :city_id, City.find(:all, :order => ‘id’), :id, :ort, :include_blank => true) %></td>
    <%= observe_field("user_city_id",
      :frequency => 1,
      :url => {:action => ‘make_ap_select’},
      :with => "user_city_id") %>
    <div id="make_ap">
      <%= render :partial => "make_ap_select", :object => @aps %>
    </div>

    _make_ap_select.html.erb

    <%= collection_select(:user, :ap_id, @aps, :id, :nodename, :include_blank => true) %>

    Controller

      def make_ap_select
        city = City.find(params[:user_city_id])
        @aps = city.aps
        if request.xhr?
          render :update do |page|
            page.replace_html "make_ap", :partial => "make_ap_select", :object => @aps
          end
        end
      end

      def create
        @user = User.new(params[:user])
        puts params[:user][:ap_id]
        …
      end

    The result in controller from "puts params[:user][:ap_id]" is ever: nil.

    Sorry for my bad english.

  40. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 -
    try:
    <%= u.collection_select(:city_id, City.find(:all, :order => ‘id’), :id, :ort, :include_blank => true) %>

    that is u.collection_select(:city_id …) instead of collection_select(:user, :city_id …)

    Also, I don’t see anything with the id of "make_ap" to allow this statement to work:
    page.replace_html "make_ap", :partial => "make_ap_select", :object => @aps

    you need something like this:

    <div id="make_ap">
    <%= render :partial => "make_ap_select", :object => @aps %>
    </div>

  41. By Frechdax75 on Mar 30, 2008 | Reply

    "make_ap" is a <div> before and after "render partial".

    I have change collection_select in u.collection_select.

    _form.html.erb

    <%= u.collection_select(:city_id, City.find(:all, :order => ‘id’), :id, :ort, :include_blank => true) %>
    <%= observe_field("user_city_id",
    :frequency => 1,
    :url => {:action => ‘make_ap_select’},
    :with => "user_city_id") %>
    <div id="make_ap">
    <%= render :partial => "make_ap_select", :object => @aps %>
    </div>

    Unfortunately the result is the same.
    On Create "puts params[:user][:ap_id]" is ever: nil.

  42. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 — also do u.collection_select for ap_id:<filter:code attributes=lang="ruby"><%= u.collection_select(:ap_id, @aps, :id, :nodename, :include_blank => true) %></filter:code>Also, examine the html ("view page source" in firefox) to see what it looks like and post that (the generated HTML) too.

    Make sure to put filter tags around the HTML you post so that we can see everything - <a href="http://pullmonkey.com/2008/7/23/open-flash-chart-ii-plugin-for-ruby-on-rails-ofc2#comment-46303">see directions here</a>.

  43. By Brian on Mar 30, 2008 | Reply

    Did you ever do the part 2? Just curious.. if so, I’d like to see it.

  44. By charlie on Mar 30, 2008 | Reply

    Hey Brian, I did do a part two - <a href="http://pullmonkey.com/2008/8/5/dynamic-select-boxes-many-to-many-ruby-on-rails">part II</a>

    Touches on many to many, not sure it followed exactly where I intended to go with part II, but it is at least another example for you to look at.

  45. By Brian on Mar 30, 2008 | Reply

    I’ve tried adding this to my own app, with two dropdowns.

    When I select an option in the first dropdown, I never make it into the update_ method. It reloads index instead.

    any idea of what to look at?

  46. By charlie on Mar 30, 2008 | Reply

    @Brian, I would start with running `rake routes` on the command line and then looking at your routes config (RAILS_ROOT/config/routes.rb).

    Also, check the logs, maybe it was a redirect or there was an error?

  47. By Frechdax75 on Mar 30, 2008 | Reply

    @charlie
    Here the html output
    <filter:code attributes=lang="html">
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <title>index</title>
    <link href="/stylesheets/layout.css?1231668968" media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/layout2.css?1231668968" media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/lightbox.css?1231668968" media="screen" rel="stylesheet" type="text/css" />
    <script src="/javascripts/prototype.js?1231668968" type="text/javascript"></script>

    <script src="/javascripts/effects.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/dragdrop.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/controls.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/lightbox.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/application.js?1231668968" type="text/javascript"></script>
    </head>
    <body>
    <table id="liste">
    <tr>
    <form action="/users" class="new_user" id="new_user" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="aabc8a8e95e763c9c8dd13d62e2b1e881bd73993" /></div>

    <!–[form:user]–>
    <th>Nickname</th>
    <td><input id="user_nick" name="user[nick]" size="30" type="text" /></td>
    <th>Passwort</th>
    <td><input id="user_password" name="user[password]" size="30" type="password" /></td>
    </tr><tr>
    <th>Strasse</th>
    <td><input id="user_strasse" name="user[strasse]" size="30" type="text" /></td>
    <th>Ort</th>
    <td><select id="user_city_id" name="user[city_id]"><option value=""></option>
    <option value="1">Mil</option>
    <option value="2">Opp</option>
    <option value="3">Dro</option>
    <option value="4">Lip</option>
    <option value="5">Wes</option></select></td>
    <script type="text/javascript">
    //<![CDATA[
    new Form.Element.Observer('user_city_id', 1, function(element, value) {new Ajax.Request('/users/make_ap_select', {asynchronous:true, evalScripts:true, parameters:'user_city_id=' + encodeURIComponent(value) + '&authenticity_token=' + encodeURIComponent('aabc8a8e95e763c9c8dd13d62e2b1e881bd73993')})})
    //]]>
    </script>

    </tr><tr>

    <th>AP</th>

    <td><div id="make_ap">
    <select id="user_ap_id" name="user[ap_id]"><option value=""></option>
    <option value="1">BR2</option>
    <option value="2">BR1</option>
    <option value="3">AP05</option>
    <option value="4">AP02</option>
    <option value="5">AP22</option></select>

    </div></td>

    </tr>
    </table>
    <!–[eoform:user]–>
    <p><input id="user_submit" name="commit" type="submit" value="Anlegen" /></p>
    </form>
    </body>
    </html>
    < /filter:code>

  48. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 — you need to take out the space < /filter:code>, between the < and the /

  49. By Frechdax75 on Mar 30, 2008 | Reply

    @charlie
    next attempt, here the html output
    <filter:code attributes=lang="html">
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <title>new</title>
    <link href="/stylesheets/layout.css?1231668968" media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/layout2.css?1231668968" media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/lightbox.css?1231668968" media="screen" rel="stylesheet" type="text/css" />
    <script src="/javascripts/prototype.js?1231668968" type="text/javascript"></script>

    <script src="/javascripts/effects.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/dragdrop.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/controls.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/lightbox.js?1231668968" type="text/javascript"></script>
    <script src="/javascripts/application.js?1231668968" type="text/javascript"></script>
    </head>
    <body>
    <table id="liste">
    <tr>
    <form action="/users" class="new_user" id="new_user" method="post"><div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="2ad37d74020c7b8b93c3e224ab9ed07b10fe0c99" /></div>

    <!–[form:user]–>
    <th>Nickname</th>
    <td><input id="user_nick" name="user[nick]" size="30" type="text" /></td>
    <th>Passwort</th>
    <td><input id="user_password" name="user[password]" size="30" type="password" /></td>
    </tr><tr>
    </tr><tr>
    <th>Strasse</th>
    <td><input id="user_strasse" name="user[strasse]" size="30" type="text" /></td>
    <th>Ort</th>
    <td><select id="user_city_id" name="user[city_id]"><option value=""></option>
    <option value="1">Milkel</option>

    <option value="2">Opp</option>
    <option value="3">Dro</option>
    <option value="4">Lip</option>
    <option value="5">Wes</option></select></td>
    <script type="text/javascript">
    //<![CDATA[
    new Form.Element.Observer('user_city_id', 1, function(element, value) {new Ajax.Request('/users/make_ap_select', {asynchronous:true, evalScripts:true, parameters:'user_city_id=' + encodeURIComponent(value) + '&authenticity_token=' + encodeURIComponent('2ad37d74020c7b8b93c3e224ab9ed07b10fe0c99')})})
    //]]>
    </script>
    </tr><tr>

    <th>AP</th>

    <td><div id="make_ap">
    <select id="user_ap_id" name="user[ap_id]"><option value=""></option>
    <option value="1">BR2</option>
    <option value="3">BR1</option>
    <option value="4">AP05</option>
    <option value="26">AP22</option></select>
    </table>
    <!–[eoform:user]–>
    <p><input id="user_submit" name="commit" type="submit" value="Anlegen" /></p>
    </form>
    </body>
    </html>
    </filter:code>

  50. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 - here is the ordering that I see:
    start table
    start form
    inputs
    select
    end table
    end form

    Your table tags need to wrap correctly, move your ending table tag outside the form.

    Seeing this, my guess is that none of your params are being sent correctly, not just the ap_id. What about params[:user][:nick], does that exist? Please post the output of params[:user].inspect.

  51. By Frechdax75 on Mar 30, 2008 | Reply

    @charlie
    Table_tags I converted, but again the result remains the same.

    If I city (city_id) does not specify, so do not observe trigger, I get in params [: user] [: ap] an issue.

    The relationship looks like this:
    <filter:code attributes=lang="ruby">
    class User < ActiveRecord::Base
    belongs_to :city
    belongs_to :ap
    end

    class City < ActiveRecord::Base
    has_many :aps
    has_many :users
    end

    class Ap < ActiveRecord::Base
    belongs_to :city
    has_many :users
    end
    </filter:code>
    Can the problem be here?

  52. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 - no, the problem is not there that looks fine. Please answer my question from before, that is where the problem is:
    Seeing this, my guess is that none of your params are being sent correctly, not just the ap_id. What about params[:user][:nick], does that exist? Please post the output of params[:user].inspect.

  53. By Frechdax75 on Mar 30, 2008 | Reply

    @charlie
    The output of params[:user].inspect is:
    {"nick"=>"123", "password"=>"123", "city_id"=>"4"}
    nick, password and city_id are correct but ap_id is missing.

  54. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 - Ah - back to your HTML, you have a form inside a ‘tr’ that also contains all your other "working" params - nick, password, city_id, but then ap_id is in another ‘tr’. Everything needs to be thought of as being in "scope".
    I would move the form outside to wrap the table:
    1) Start Form
    2) Start Table … put all your form elements here …
    3) End table
    4) End Form

  55. By Frechdax75 on Mar 30, 2008 | Reply

    @charlie
    Thanks, the problem is solved.

    1. Start Form
    2. Start Table
    3. End Table
    4. End Form
    works.

    But why does
    1. Start Table
    2. Start Form
    3. End Form
    4. End Table
    not works?

  56. By charlie on Mar 30, 2008 | Reply

    @Frechdax75 - that would work too, but you have to put the entire form inside your ‘td’, you can’t start a form in one ‘td’ and end it in another. That is why it is just best to wrap the table with the form.

  57. By Raavin on Mar 30, 2008 | Reply

    Hey there,

    I’ve implemented a related country/region select where region is populated when a country is selected.

    The problem is thatt, in your tutorial, everything (:all) is loaded into the selects then drilled down when you manually select something.

    I need to be able to have the region select start empty when creating a ‘new’ address and filled base on country when updating in ‘edit’.

    The other problem is that regions also fills when the page refreshes after it is caught by the validator.

    None of this would be a major problem with a small data set but the are roughly 3500 regions.

    Any ides would be great.

    Cheers,

    Jason

  58. By charlie on Mar 30, 2008 | Reply

    @Jason - two things that may work for you:
    1) you could just change it from @regions = Region.all to @regions = [] or

    2) do (1) and disable the regions select box then in the remote_function you could enable it in a complete hook as in :complete => this.enabled (pseudo code).

    For more info, check the callbacks here - http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M001613

  59. By Raavin on Mar 30, 2008 | Reply

    Hey there Charlie,

    Thanks for the tip. I ended up using

    <filter:code attributes=lang="ruby">
    @regions = Region.find(:all, :conditions => {:country_id => @address.country_id}, :order => :name)
    < /filter:code>

    in new, edit & create

    Seemed to work.

    Cheers :)
    Jason

  60. By Javix on Mar 30, 2008 | Reply

    Nice tutorial; There is just one thing to change: if you select a Genre, - Artists are reloaded, - it’s OK. If you unselect Genre and choose again ‘Select a Genre’, - the Arists list is never updated. The same is to do for Songs. Is it possible to reload artists and songs if you select ‘Select a Genre’/'Select an Artist’? Thank you!

  61. By charlie on Mar 30, 2008 | Reply

    @Javix - sure, if the genre can’t be found, meaning genre = Genre.find(params[:genre_id]) is nil or errors, then the user must have selected the prompt "Select a Genre" and at this time we can say artists = Artist.all and songs = Song.all. The partials should take care of the rest.

  62. By Ariel on Mar 30, 2008 | Reply

    Hi, This is the most clear tutorial about dynamic select boxes. Finally I Could work with replace html.

    Thanks for this!

    I am super newby, and still stuck with a little matter, how can I pass the values from the partial to the form ?

  63. By kikito on Mar 30, 2008 | Reply

    Hi everyone,

    Just so you know, there’s a plugin called dependent_select (http://github.com/splendeo/dependent_select/tree/master) that does something similar to this, only without AJAX (it stores everything on a big javascript array at the begining)

  64. By Jach on Aug 31, 2009 | Reply

    Excellent! It helped me out, when I use a dynamic checklist below the select box

  65. By Andrew on Oct 22, 2009 | Reply

    hi there
    I think you need to be more thorough with your work.
    I followed all the instructions there and could not get it to work.

    This is not helpful for people making the move over to rails.

    The least you are lacking are:
    - proper routes set up (ie. firing up http://localhost:3000 on the browser doens’t work ie brings me to an invalid page)
    - you need to specify “rake db:create” first other wise, how the hell would “rake db:migrate” work????

    Please clean up your tutorial. It’s very helpful (as in , controlling the genre, artist and songs) but please complete it .
    thanks

  66. By pimp daddy on Oct 27, 2009 | Reply

    damn andrew
    there was no need to pimp slap the guy for this article. there is a basic assumption that everyone who reads this knows a little bit of something about rails. if your localhost isn’t showing up, then you have other configuration problems with your machine. the assumption is that your rails environment has already been created.

  67. By charlie on Oct 27, 2009 | Reply

    Thanks pimp daddy …

    Andrew -

    Proper routes? - not even necessary … just use http://localhost:3000/test_it. The route has already been defined. The basics of rails will teach you that the default routes allow us to get to any controller and action by using ‘:controller/:action’. This is documented already, I didn’t feel that it needed repeating.

    rake db:create? I’m surprised you didn’t jump all over me for failing to mention that you need to use the rails command to create your project. Thanks for taking it easy on me :)

    It’s obvious you are having a tough time adjusting to something new and felt like taking it out on this article (and me). We’ve all been there, give it some time, its called learning - hopefully you will get used to it.

    Just keep in mind that I don’t work for you or with you, I don’t know you - I just wrote an article to show you something new over a year and half ago.

  68. By Cecille on Oct 27, 2009 | Reply

    hello.

    first of all, great tutorial.

    just have some inquiries:

    i have 4 select menus

    first one is country select menu
    second is region select menu
    third is province select menu
    fourth is city select menu

    i also have text_field for street

    what i wanted to happen were:

    1. to dynamically populate second select menu based on the value selected from the first select menu, then dynamically populate the third based on the second and so on.

    2. then if the value from the first select menu doesnt have sublocations for second select menu the select menu will not be displayed.

    3. however if in the third or the province select menu the value selected doesn’t have sublocations(cities) then a textfield for city must be displayed instead of the select menu for city and simultaneously the text_field for street will be displayed

    4. if I select a different value in the first select menu the second, third, fourth and the text field must disappear, but if I select different value in the second select menu the third, fourth and the text field must disappear but the first must stay.

    what changes should I make to implement the above situations?
    please help me. thanks!

  69. By wojtek on Nov 12, 2009 | Reply

    Hi.

    Just to let you know I did a similar thing using observer approach.
    Any comments appreciated.

    http://programmers-blog.com/2009/11/12/dependant-dropdowns-select-menus-using-rails

  70. By varsha on Nov 23, 2009 | Reply

    i loved this tutorial. i had been struggling to write similar code as i m a newbie in rails. you have explained it really well . moreover having working example makes it easier to understand.

  71. By SaveTimE on Dec 8, 2009 | Reply

    Hello,
    nice tutorial. Best for dynamic selectboxes.
    It works fine for ‘index’ and ‘new/create’, but I’am struggeling with the ‘update/edit’ actions.
    Can someone post a code snippet for the update action or/and explain how it works?
    I’am still a Newbie and not yet very close with Ruby and Rails.
    Also it would be helpfull to have an example for a ‘destroy’ action which only allows to delete a genre/artist if there is no song record to that artist or genre.

    Thanks a lot

    SaveTimE

  72. By SaveTimE on Dec 8, 2009 | Reply

    Hi again,
    actually, i think my problem is that I want to add for every song first one genre and than one artist. So I don’t want the genres_controller to handel the selectboxes, instead I want the songs_controller to handel these requests.
    Any advise what and how is needed to be modified the example?

    Thanks
    SaveTimE

  73. By charlie on Dec 8, 2009 | Reply

    So you are creating and editing songs and want to associate an artist and genre to it?

    I think it would be done in the artists’ form, add a song to the artist.
    artists/1/songs/new (which would use the songs_controller)
    artists/1/songs/1/edit

    To get the routes above, you would use has_many in your routes:
    map.resources :artists, :has_many => :songs

    By adding an artist to your song, you will automatically get the genre, since the artist belongs_to :genre.

    Is this what you are after?

    For destroy, you can do the check in the controller action, here is an example for the artists controller:
    def destroy
    @artist = Artist.find(params[:id])
    if @artist.songs.empty? and @artist.destroy
    flash[:notice] = “Artist has been deleted”
    else
    flash[:error] = “Can’t delete this artist …. ”
    end
    redirect_to :back
    end

    You could also handle this in the artist model using before_destroy to check.

  74. By SaveTimE on Dec 9, 2009 | Reply

    Thanks Charlie,
    you got the point. I manage to find a solution. It is only needed to modify the ‘update_artist’ action and and to create a new one ‘update_genres’ and a new partial ‘genres’
    here the example for songs_controller.rb:

    def update_artists
    # updates artists based on song selected
    genre = Genre.find(params[:genre_id])
    artists = genre.artists
    render :update do |page|
    page.replace_html ‘artists’, :partial => ‘artists’, :object => artists
    end
    end

    def update_genres
    # updates genre based on artist selected
    genres = Genre.find(:all, :conditions => ["artist_id =?", params[:artist_id]])
    render :update do |page|
    page.replace_html ‘genres’, :partial => ‘genres’, :object => genres
    end
    end

    All other code is similar to the example

    The new partial:

    “Select a Genre”},
    {:onchange => “#{remote_function(:url => {:action => “update_artists”},
    :with => “‘genre_id=’+value”)}”}) %>

    The destroy action example is very helpful.
    Thanks again

  75. By Marc Luzietti on Dec 17, 2009 | Reply

    What ever happened to the demo?

  76. By Hilman Zaky on Jan 5, 2010 | Reply

    Big thanks.. it’s really helpful while I got problems with “country-state-city” drop down list..

  77. By Jose Juan Delgado B. on Mar 9, 2010 | Reply

    Excelente tutorial, me ayudo a entender collection_select y voy aplicar esta tecnica en validaciones, muchas gracias.

  78. By Tetsu Nakashima on Apr 18, 2010 | Reply

    Thanks a lot for such a wonderful tutorial. Lean and easy to follow

    You explained very well the key concepts. I wish more “tutorials” were like yours!!
    ;^D

    Cheers!
    –TN

  79. By Andrew on Jun 10, 2010 | Reply

    Charlie,

    You Rock! Such a simple, straight forward tutorial. Now I’m gonna finally finish what I’ve been trying to do for the past 2 days..

    Now get off your chair and tear it up on your new bike!

    Thanks,

    Andrew

    For those who are new to Ruby… Take the plunge and follow this tutorial, it works.

  80. By Wim on Jul 20, 2010 | Reply

    I just want to say thanks for this tutorial, I got it working in Rais2 within 10min!

    Now however (perhaps foolishly) I have upgraded to Rails3 and I just cant get it to work. It seems that the collection_select method no longer will allow an object input.

    Has anyone here been able to get it to work with Rails3?

    Thanks in advance,

    Wim

  81. By Daniel K. Lima on Dec 9, 2010 | Reply

    It’s the only tutorial that really works, wanna say thank you.

    I got it working on Rails 3.0.3.

    The only think I had to change was about the partial:

    View:

    ’song’, :locals => { :songs => @songs } %>

    Partial _song.html.erb:

    “– select a song –”}) %>

    – choose –

  82. By Daniel K. Lima on Dec 9, 2010 | Reply

    It’s the only tutorial that really works, wanna say thank you.

    I got it working on Rails 3.0.3.

    The only think I had to change was about the partial:

    View:

    ’song’, :locals => { :songs => @songs } %>

    Partial _song.html.erb:

    “– select a song –”}) %>

    – choose –

  83. By Daniel K. Lima on Dec 9, 2010 | Reply

    How to add code?

  84. By Daniel on Jan 13, 2011 | Reply

    I see this is quite an old post.Still I really like the way is written.
    I tried this example on rails 3 and it just didn’t work.By “didn’t work” I mean that the page loads and shows me the three select menus…but when I change the values nothing happens,nothing gets updated.What am I missing?.

  85. By charlie on Jan 14, 2011 | Reply

    I am not sure what is wrong, but since it is JS, it is probably a JS error of some sort, could you launch it in firefox and use the firebug console and report what you see?

  86. By Daniel on Jan 14, 2011 | Reply

    …These are the moments that I love (hate) the most…I was lunching the app on another machine with chrome.Just installed there firefox and run it….works!.Went back to chrome…also works!!.

    Again thx for the good example!

  87. By James on Mar 3, 2011 | Reply

    Thanks for the great tutorial. I’m fairly with RubyonRails and have been trying to figure how to create dynamic select boxes for a while now.

    Following your tutorial, I ran in to a routing error (I’m pretty sure I’m missing something in my routes.rb file)

    This is my error:

    No route matches {:controller=>”test_it”, :escape=>false, :action=>”update_artists”}

    and was raised from this line:

    “Select a Genre”},
    {:onchange => “#{remote_function(:url => {:action => “update_artists”},
    :with => “‘genre_id=’+value”)}”}) %>

    Your help would be greatly appreciated.

    Thanks

  88. By James on Mar 3, 2011 | Reply

    Actually, just figured it out.

    Great Tutorial!

  89. By chip on Mar 9, 2011 | Reply

    @James - I am getting the same error — how did you fix it?
    Thanks

  90. By Krishna on Apr 3, 2011 | Reply

    @chip
    it worked when I added to routes.rb

    post “testit/update_artists”

    post “testit/update_songs”

    Note:my controller name is testit and not test_it.

  91. By spatchcock on Apr 17, 2011 | Reply

    Worked a treat for me. Thank you.

  92. By olivier on May 23, 2011 | Reply

    The sample works quite well. When i adapt it to my legacy database which uses its own foreign keys and own primary, it errs telling me that the specified column (the foreign key) does not exist, and yet it does!
    kinda lost…
    Sincerely

  93. By Akela_sil on Oct 1, 2011 | Reply

    Hello

    Thanks for the tutorial, I find it very useful, but I have a problem doing my final project. I have several days with and I can not fix it. I hope I can help.

    My code:
    migracion: create_obras.rb
    class CreateObras < ActiveRecord::Migration
    def self.up
    create_table :admin_obras do |t|
    t.string :titulo
    ……
    t.references :admin_coleccion
    t.references :admin_artistum
    t.references :admin_seccion
    t.references :admin_tecnica

    t.timestamps
    end
    end

    migracion: create_admin_seccions.rb
    class CreateAdminSeccions < ActiveRecord::Migration
    def self.up
    create_table :admin_seccions do |t|
    t.string :nombre

    t.timestamps
    end
    end

    migracion: create_admin_tecnicas.rb
    class CreateAdminTecnicas < ActiveRecord::Migration
    def self.up
    create_table :admin_tecnicas do |t|
    t.string :nombre
    t.references :admin_seccion

    t.timestamps
    end
    end

    Is stored in: (… = controller or views …)
    app/…/admin/obras
    app/…/admin/tecnicas
    app/…/admin/seccions

    Models:
    class Admin::Tecnica “Seccion” # foreign key - admin_seccion

    class Admin::Seccion “Obra” # Están en el mismo espacio de nombres
    has_many :admin_tecnicas, :class_name => “Tecnica”

    class Admin::Obra “Seccion” # foreign key - admin_seccion

    Controller: #### THIS IS PROBLEM ####
    def update_tecnicas
    admin_seccion = Admin::Seccion.find(params[:admin_seccion_id])
    admin_tecnicas = admin_seccion.admin_tecnicas #### THIS IS PROBLEM ####

    render :update do |page|
    #page.replace_html ‘tecnicas’, :partial => ‘/admin/obras/secciones’, :object => @admin_obra
    end
    end

    _secciones.html.erb:

    “Seleccione una sección”},
    {:onchange => “#{remote_function(:url => {:controller=>”seccions”, :action => “update_tecnicas”},
    :with => “‘admin_seccion_id=’ + value”)}”}) %>

    He tells me the following error:
    Started POST “/admin/seccions/update_tecnicas” for 127.0.0.1 at Sat Oct 01 20:27:28 +0200 2011
    Processing by Admin::SeccionsController#update_tecnicas as JS
    Parameters: {”authenticity_token”=>”1PXjFEx0a/ngBXIVA7EMp5SVujhffa3AkxU6w130Acc=”, “_”=>”", “admin_seccion_id”=>”1″}
    Admin::Seccion Load (0.1ms) SELECT `admin_seccions`.* FROM `admin_seccions` WHERE `admin_seccions`.`id` = 1 LIMIT 1
    Admin::Tecnica Load (0.5ms) SELECT `admin_tecnicas`.* FROM `admin_tecnicas` WHERE (`admin_tecnicas`.seccion_id = 1)
    Mysql::Error: Unknown column ‘admin_tecnicas.seccion_id’ in ‘where clause’: SELECT `admin_tecnicas`.* FROM `admin_tecnicas` WHERE (`admin_tecnicas`.seccion_id = 1)
    Completed 500 Internal Server Error in 24ms

    ActiveRecord::StatementInvalid (Mysql::Error: Unknown column ‘admin_tecnicas.seccion_id’ in ‘where clause’: SELECT `admin_tecnicas`.* FROM `admin_tecnicas` WHERE (`admin_tecnicas`.seccion_id = 1)):
    app/controllers/admin/seccions_controller.rb:106:in `write’
    app/controllers/admin/seccions_controller.rb:106:in `print’
    app/controllers/admin/seccions_controller.rb:106:in `update_tecnicas’

    Rendered /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.9/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.2ms)
    Rendered /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.9/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (81.0ms)
    Rendered /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.9/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (86.3ms)

    I await your favorable support.
    Thank you

    Regards

  94. By Akela_sil on Oct 1, 2011 | Reply

    THIS:
    Mysql::Error: Unknown column ‘admin_tecnicas.seccion_id’ in ‘where clause’:
    SELECT `admin_tecnicas`.* FROM `admin_tecnicas` WHERE (`admin_tecnicas`.seccion_id = 1))

    SHOULD BE, but do not know how:

    SELECT `admin_tecnicas`.* FROM `admin_tecnicas` WHERE (`admin_tecnicas`.admin_seccion_id = 1))

    Thank you

  95. By Akela_sil on Oct 2, 2011 | Reply

    Solution:

    class Admin::Seccion “Tecnica”, :foreign_key => “admin_seccion_id”

    end

  96. By Akela_sil on Oct 2, 2011 | Reply

    My code does not ship well, so I go back to writing. Sorry.

    My solution has been:

    << class Admin::Seccion >

    < “Tecnica”, :foreign_key => “admin_seccion_id” >>

    <>

    Thank

  97. By ramya on Oct 18, 2011 | Reply

    Hi,

    Please let me know if routes are to be created for update_artists and update_songs.I am getting No route matches error.

  98. By ramya on Oct 18, 2011 | Reply

    Hi,

    I added the route through routes.erb. Now I am getting the error “Ajax undefined”. I am not able to the code hitting the update_releases in my controller.
    I have projects which contains releases which in turn contains cycles.

  99. By charlie on Oct 18, 2011 | Reply

    Yes, you do need to specify the routes now. At the time of writing, there was a catch-all mapping for any :controller/:action that was not previously handled.

  100. By charlie on Oct 18, 2011 | Reply

    This article was also written at a time when prototype was included. You’ll need to make jQuery modifications.

  101. By ramya on Oct 18, 2011 | Reply

    Thanks a lot Charlie. I have made all the necessary jquery modifications.
    I am getting error due to this line.

    page.replace_html ‘artists’, :partial => ‘artists’, :object => artists
    page.replace_html ’songs’, :partial => ’songs’, :object => songs

    “Element doesn’t support this property or method” error is seen which is displayed as a pop up on changing the value of the drop down list box.

  102. By Foluso on Jul 30, 2012 | Reply

    Thanks for this tutorial.
    I am working on rails 3.2 and I got this error when I navigated to http://localhost:3000/dynamic (dynamic is the name given to the controller)

    undefined method `remote_function’ for #<#:0xa033f68>

    What should I do?

  103. By charlie on Aug 4, 2012 | Reply

    Foluso - “remote_function” was the old way, this tutorial is over 4 years old :)

    Everything has moved away from prototype and to unobtrusive JS with jquery.

    So now you would do something like $(’#artist_id’).change(function() { do your jquery ajax call here });
    Also, you’ll need to change the render :update bits. Just create a actionname.js.erb file in your views path for the controller. Then move the code from within the render :update block to the js.erb file, making whatever necessary changes.

    I’ll see about doing a 2012 version of this tutorial.

  104. By Akerele Foluso on Aug 6, 2012 | Reply

    Thank you for your reply Charlie, could you kindly elaborate in clear terms on what changes to make and in which files to do I need to make these changes using your code as guide because I am a rails learner and thus cannot figure out your explanation in the previous post. I will really appreciate if you could start from the controller action or better still provide us a new tutorial as you opined that clearly explains this concept.

    This has been giving me real though time for more than a week now and I will really appreciate your help in this regard and I am pretty sure it will be helpful to lots of people out there too.

    Thanks.

  105. By Bob Hazlewood on Aug 9, 2012 | Reply

    An updated version of this tutorial would be GREATLY appreciated. With so many of the “examples” I see on the web, I can’t tell what’s “actual” code and what is someone’s pseudo-code.

  106. By charlie on Aug 11, 2012 | Reply

    The updated version is now available, go check it out.

Sorry, comments for this entry are closed at this time.