Related Drop-down Lists with Ruby on Rails and AJAX

Note: I have been meaning to re-write this post to make better use of Ruby on Rails helpers, etc. When I first wrote this I was extremely new to Rails and my unfamiliarity with the framework showsUntil I have the free time to re-write this post, please bear with what is currently here and leave comments to help others that follow after you.

Finally! I’ve been working on this little bit of Ruby code for hours now, all because of some odd bugs (which, when I learn Ruby better, will probably cease to become odd) and a lack of good Ruby on Rails documentation.

What I’ve been working on is getting two related HTML drop-down lists to update properly using the built-in Ajax support in Ruby on Rails. Specifically, when the user selects an Artist from the first drop-down list, only that artist’s Albums should be listed in the second. I wanted to do this without having to retrieve all of the albums during the initial page load and without having to do a post back when the user selects an artist. So, that’s where Ajax comes in. Ajax uses the JavaScript XMLHTTPRequest routine to retrieve new data from the server without requiring the user to refresh the webpage.

Some gotchas for the new Ruby programmer / web developer:

  • You cannot modify the InnerHTML of a select drop-down list. Instead, you have to modify the InnerHTML of the div that _contains_ the select drop-down list, and when you do you have to recreate the whole drop-down.
  • When you are using instance variables (those that begin with the @-sign), ensure that the instance variable exists before trying to use:
    @variable += “value”
    syntax or else Ruby will throw up an error. For example, before that statement, add a line that reads:
    @variable = “”
  • When concatenating strings that contain instance variables, Ruby is picky in a way that I can’t fully describe. For example, the following does not work:
    @html += “<option value=’” + @album.id + “‘>” + @album.album_name + “</option>”
    But this does work:
    @html += “<option value=’#{@album.id}’>#{@album.album_name}</option>”

Anyway, this is the troubled code that _did not_ work:

admin_controller.rb
@albums = Album.find_all_by_artist_id(@params["artist_id"])
@html = "<select id='album_id' name='album_id'>"
@html += "<option value=''>No Album</option>"
@albums.each do |@album|
   @html += "<option value='" + @album.id + "'>" + @album.album_name + "</option>"
end
@html += "</select>"

After hours I got it working with this code:

admin_controller.rb
@albums = Album.find_all_by_artist_id(@params["artist_id"])
@html = "<select id='album_id' name='album_id'>"
@html += "<option value=''>No Album</option>"
@albums.each do |@album|
   @html += "<option value='#{@album.id}'>#{@album.album_name}</option>"
end
@html += "</select>"

But, this has to be coupled with the RHTML code in the template, as follows.

add_song.rhtml
<%= javascript_include_tag "prototype" %>

Artist
<select name=”new_song[artist_id]” id=”new_song[artist_id]”>
   <option value=””>Select Artist</option>
   <% @artists.each do |artist| %>
      <option value=”<%= artist.id %>”>
         <%= artist.first_name %> <%= artist.last_name %>
      </option>
   <% end %>
</select>

Album
<div id=”album_id_container”>
   <select name=”new_song[album_id]” disabled=”disabled”>
      <option value=””>No Album</option>
   </select>
</div>

<%= observe_field("new_song[artist_id]",
   :frequency => 0.25,
   :update => "album_id_container",
   :url => { :action => :add_song_artist },
   :with => "'artist_id='+value") %>

Another site of mine is focused on collecting sports cards. For card collectors there are many great San Diego sports card stores to find both ultra modern and vintage baseball, basketball and football sports cards.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *