Related Drop-down Lists with Ruby and Ajax 50
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") %>
[...] at I’ve never created a web control before, let alone create one that uses AJAX. But I have used AJAX in my Ruby on Rails site before, although I’ll admit that the experience won’t be all [...]
You can build the option list with:
“name”) %>
But I cannot get the observe_field to trigger anything from the dropdown list. How did you manage this?
Are you sure that the observe_field is not triggering the action? You can try just outputting some debug lines from the action to your WEBrick console to see if you’re actually getting into the action.
Unless you are specifying the wrong form field for it to observe, I can’t readily think of a reason why it wouldn’t trigger. The observe_field tag is pretty straightforward.
Hello,
I was wondering if you had the whole source for this. Iam learning ruby/rails and would like to test your example. Can you please email me the test source? Thanks for your help.
Sunder
Hello,
Iam unable to get the observe_field tag to trigger any action either. Do you have any input?
Sunder
Hi Sunder,
I have emailed you my code. I hope it helps.
Also, are you sure that you are including the Prototype javascript library?
It should probably be in the portion of your view.
Hi, would you mind sending the code to me too? Thanks a lot
Actually, perhaps that’s not necessary. Sunder was able to eventually get his code working after making one change: for this to work in Firefox you need to set the ID of the first <select> element so that it matches what you have set in the observe_field tag.
Hello,
could you had the whole source for this to me.
thanks alot
leo
Hi guys,
Sending source code around is something I’m not interested in doing. If what I’ve written is not sufficient to get you going, then there are other great resources available on the Net to turn to.
Best of luck.
Howdy
While looking for select work arounds, i came across your site:
@albums.each do |@album|
@html += Ҡ+ @album.album_name + “â€
You should not have the |@album| definition in the first line, it should just be |album| and then in the second line you can reference the album.id variable directly.
which is what you did for the artist outline
the first line reads (i think) for each “album” in the @albums collection, do the following. When you use the @ directive it’s declaring a new container, which is not what you want to do, the container comes pre-made with the .each call.
Slowly, i am coming to an understanding of this things they call Ruby on Rails
ruby doesnt expand the #{ ..} inside the single quote.I think that happens in ” ” and in the backtick ` `.. my study of ruby started with rails
so i am no ruby expert ;-)
Does this:
@html += Ҡ+ @album.album_name + “â€
Give you an type error?
Use @album.id.to_s instead. You cannot concatenate a string and an integer.
Ahh, that very well may have been what the issue was.
I tried the stuff like mentioned but each time the second select box keeps expanding in size!! has anyone observed this ? I just cant seem to figure out the problem without going cross-eyed reading the code;-)
My controller is here
def get_cities
@html = “”
if (params[:country_id].to_s == “India”)
@html += “New Delhi”
else
@html += “Atlantis”
end
@html += “”
f= File.open(’/tmp/select.log’,”w”);
f @html
end
end
My View is here
Countries
India
Other
0.25,:update=>’cities’,
:url=>{ :action => ‘get_cities’},
:with=> “‘country_id=’ + value” ) %>
Hi Vivek,
Can you please repost the code you used in your view to represent the two select boxes?
You may need to replace all greater than signs and less than signs with their html entity equivalents (> and <)
Just curious…
Why are you generating HTML in your controller? Shouldn’t that be reserved for views? Or am I missing something here?
Well, I’m sure there are other, less coupled methods of doing it. Actually, I know there are. But due to how the prototype is built into RoR (at least, how it was built into RoR when I wrote this code), it assumes you are returning HTML from the AJAX call, rather than XML. So that is why I generated HTML in my controller.
[...] ;m not sure what I’m missing. I followed closely the examples from a couple of posts. It seems like it should work but for now I’m stuck. This entry was [...]
Hi,
I’m a newbie at RubyonRails, and while trying to get some related drop-down lists to work at my website, I’ve found this webpage whose solutions I’ve been trying to follow. Although my efforts, I’m finding some dificulties. Maybe you could help me.
my user_controller.rb
def index
@artists_array = Artist.find(:all, :order => “name”).map {|c| [c.name, c.id]}
end
def select_album
@albums = Album.find_all_by_artist_id(@params["artist_id"])
@html = “”
@html += “No Album”
@albums.each do |album|
@html += “#{album.nome}”
end
my index.rhtml
Artists
Albums
No Album
0.25,
:update => “album_id_container”,
:url => {:action => :select_album},
:with => “‘artist_id=’+value”)
%>
When I first choose one of the artists I get the following result:
Missing template ./script/../config/../app/views/user/select_album.rhtml
I apreciate your help.
my code (which seems to work):
the view (_form.rhtml):
Category
Subcategory
No Subcategory
0.2,
:update => “select_subcategory”,
:url => {:action => :filter_subcategory},
:with => “‘account_category_id=’+value”) %>
controller:
def filter_subcategory
@subcategories = Subcategory.find_all_by_category_id(@params["account_category_id"])
render :partial => ’select_subcategories’, :object => @subcategories
end
partial view (_select_subcategories.rhtml):
Subcategory
i´ve had some problems with the mentioned code from above.
just wanted to post my code here – maybe it´s helpful for somebody.
hmm, posting code didn´t seem to work.
Regarding the select problem, apparently it’s a problem with IE 5,6 DOM model. It some how doesnt update properly if you update the select object’s inner html. It’s as if the select object disappeared. If you use the same method on FF, it actually works. (I’ve not tried other browsers as I’m not primarily targetting them for my app.)
One workaround which I used was to directly preload all the necessary data for the dropdown lists, and use the onChange event to trigger the functions that do the deleting and adding of option items on the fly.
The implementation of dropdown list using Ruby On Rails is not really working. I want to know about the database stucture of the list items as per the above code. ll someone kindly shed some fresh light into the use of dropdown list in a little detail.
I m a newbie to Ruby On Rails.
I m facing the prob similar to one wid Mr. Rodrigo.
Already spend a complete day for the prob……
Kindly help. I m pasting the code below:
++++ location.rhtml++++++++
Artist
Select Country
“>
Album
No City
0.25,
:update => “city_container”,
:url => { :action => :find_cities_for_country },
:with => “‘country=’+value”) %>
++++++++end location.rhtml++++++++
++++++++city_controller.rb++++++++++++
def find_cities_for_country
@places = Place.find_all_by_country(”@params[:country]“)
@html = “”
@html += “No Album”
@places.each do |@place|
@html += ” #{@place.city} ”
end
@html += “”
end
+++end+++++
using database tables : places(id,city,country) and nations(id, country).
Thanx for ur consideration and help in advance.
ll b gr8ful.
What do you put in the view to show the @html string….I’ve been having trouble finding the answer. I’m sure it’s trivial
Hmm… I dunno where the last line of the function went, but it should be:
render_text @html
That’ll pass the HTML back to the view and the AJAX call will update the innerHTML of the div with it.
Great thanks…however I’ve found when I build the @html string in the controller..nothing comes back to the view.
I now have the @html string being built in a seperate view, and it seems to work. However it is creating an entire replica of the page inside the div. Basically the method that is called by the observe_field command contains nothing. Then it goes to the view associated with the method and creates the html string. I know this isn’t following the rules. But it’s the only way I can get the html string to show up.
I would verify that the observe_field tag has the correct name of the div that you are updating.
I would also try having only one line in the method that it is calling, something like render_text “test”, to see if even the word “test” is returned to the page.
If that doesn’t work, then I dunno what to tell you. You could try using the puts command to echo text to the console to ensure that you’re actually executing the AJAX method.
Yeah I tried a bunch of tests but to no avail. So I am fine having the html constructed in the view. And it is working.
Now I am trying to have this newly ajax created Select also observed to create a grandchildren select box based on what you selected in the child select that was just populated. And so forth down the chain. Haven’t gotten it working yet. Do you know if this is possible. Because the html is created dynamically I’m not sure if Rails is able to observe that field.
Any suggestions?
Well I managed to have as many child select boxes created and being observed. After I created the html for the select box I also add an observe field tag related to the newly created select and it works fine!
Chris,
I tried by adding to the @html string after the select, the observe field for the parent. I have had no success yet on how to populate the grand-child of the chained selects.
Will you be able to post the code that worked for you?
Regards.
Has anyone been able to get the similar logic working but w/ select based commands that are using the ActiveRecord? I can’t get the observe_field to monitor and I have tried everything – select_tag, different ID/Name paramaters, etc… Here is an example of my select:
this is the basic rails generated select and I want to observe it and filter a second drop down based on the selection (same example – just bound to db).
No matter what I do, I continously get a “Form is not defined” error.
Any ideas?
The select statement failed to post:
select (:user_story, :product_id, Product.find(:all).map {|p| [p.name, p.id] } )
Using observe_field method is a bad idea from the beginning!
It keeps checking the field constantly, which is unnecessary.
I’d call it “microsoft approach” or “let’s slow the world down” ;)
There is a method called remote_function
Here is the sample:
Region
‘Select region’ },
:onchange => remote_function(:update => ‘districts_for_suburb’,
:url => { :action => ‘create_districts’ })
%>
Good luck
I think that if you don’t specify a frequency parameter, observe_field acts as an onchange event, rather than a timed updater.
@Mo: You need to make sure to include the javascript reference in your tag: . That’s why you’re getting that Form error.
I am experiencing difficulties retrieving information from the related dropdowns.
I can save information in the database (the Country_id and State_id are getting saved in the Address table).
However on the edit/update screen, the information from the first “Country” dropdown is getting retrieved
properly but nothing is getting displayed in the second related “State” related dropdown.
I am using observe fields to retrieve data for the second drop down. Please advise how to prepropulate information for the second drop down based on the “id” stored in the database.
Thanks
Please help
I
I don’t know if anyone mentioned this, but the observe_field tag has to be AFTER the element it’s observing has been declared. I agree with Igor anyway – I don’t like observe_field in most cases…
Also, the acts_as_dropdown plugin clean up the line:
Product.find(:all).map {|p| [p.name, p.id]}
letting you replace it with
Product.to_dropdown
Much cleaner :-)
–YY
[...] Rory Hansen » Related Drop-down Lists with Ruby and Ajax (tags: rails ruby RubyOnRails ajax) [...]
can anyone get the code for dynamic drop down lists to put that on view page using rubyonrails…
like one drop down list consists list of states and other drop down list should contain list of states… and on selection of state from the first drop down list, the options in the second drop down list should change….
if any one can code for this i vll b thankful….
how do i see the recent comments in here???
class AdminController :city_name,
:clear => ['area_id']})
end
end
def city_update
return unless request.xhr?
areas = State.find( :all, :conditions => ["city_id=?", params[:ecosite_index]])
flash[:notice]=”#{params[:ecosite_index]}”
render :update do |page|
page :area_name} )
end
end
def index
@states=State.find_by_sql(”select distinct name,state_id from states”)
end
end
Hi thanks for the advice on this article. There just one thing I get this error when using your code:
syntax error, unexpected tIDENTIFIER, expecting kDO or ‘{’ or ‘(’
For this line:
@html = “â€
Other than the id and name changes theres no difference. Do you understand what the problem is? Many thanks. Lyn
Hi, i’m having problem trying to use observe_field: my view is like this
“type_id”,
:with => “id”, :url => { :controller => “event”,
:action => “category_changed” } %>
in the controller i’m updating @types(with query to DB),but is this enough,or i’m missing something?type drop-down is always empty!I don’t want any html inside my controller
Tnx.
my view:
“type_id”,
:with => “id”, :url => { :controller => “event”,
:action => “category_changed” } %>
you can put your layout in a partial – keeping the view out of the controller.
Using the inline form above, you’d call:
render( :text => @html )
Instead, you can call:
render( :partial => ‘partial_name’, :layout => false ).
The layout file lives in the same dir as the other views for this controller and must be named
_partial_name.js.erb
That is some ugleeeeee code. The rails way is to avoid instance variables like the plague and instead reference ActiveRecord objects.
Hi!
I would like extend my SQL capabilities.
I red that many SQL books and want to
read more about SQL for my work as mysql database manager.
What can you recommend?
Thanks,
Werutz
dear guys,
can u give a FULL and WORKING code.
or the best reference link
I stuck on AJAX on RoR….:((
http://banners.servized.com/current/gif/ed_720×90_1.gif
http://s03.radikal.ru/i176/0912/57/a8e634dad754.jpg
6]Sulfamethoxazole and Trimethoprim tablet
5]What is this medicine?
SULFAMETHOXAZOLE; TRIMETHOPRIM or SMX-TMP is a combination of a sulfonamide antibiotic and a younger antibiotic, trimethoprim. It is against to treat bacterial infections. It is also worn to obviate infections in people who are at risk. It want not on in search colds, flu, or other viral infections.
What should my fettle anguish professional certain ahead I subsume this medicine?
They have need of to cognizant of if you obtain any of these conditions:
* anemia
* asthma
* being treated with anticonvulsants
* if you repeatedly wet one’s whistle alcohol containing drinks
* kidney infection
* liver affliction
* low uniform of folic acid or glucose-6-phosphate dehydrogenase
* poor nutrition or malabsorption
* porphyria
* severe allergies
* thyroid disorganization
* an strange or allergic feedback to sulfamethoxazole, trimethoprim, sulfa drugs, other medicines, foods, dyes, or preservatives
* pregnant or infuriating to arrest pregnant
* breast-feeding
http://s52.radikal.ru/i135/0912/a3/82e1520c703c.jpg
http://s51.radikal.ru/i133/0912/10/f4c74667e9c4.jpg
bactrim preis
buy bactrim in englandside effects of bactrim
bactrim uk salespurchase generic bactrim onlineoral bactrim
bactrim ds dosewhere can i buy herbal bactrim
generic bactrimbuy bactrim without a credit carBactrim Discount Online
buy bactrim no rxbactrim dose for mrsa
buy cheap bactrim without prescriptiontaking celebrex and bactrim togetherbactrim suspension dosis
buy generic bactrim onlinebactrim prescription
bactrim no prescription to buybactrim ds antibioticbactrim uk
order bactrim usabactrim wholesale
buy bactrim pay codorder generic bactrimgeneric discount bactrim
where can i buy bactrim without prescriptionachat bactrim
Discount Bactrim UKgeneric discount bactrimbactrim usa
generic bactrim onlineOnline Bactrim CA
bactrim cheap mexicanbactrim buy online in stockbactrim ds dosage
bactrim usabactrim ds dosage
no rx bactrimlight sensitivity with bactrimachat bactrim
buy cheapest bactrimbuy bactrim online with a debit card
bactrim purchasebactrim side effectwholesale bactrim cheap
generic discount bactrimprezzo bactrim
buy bactrim in the ukGet Bactrim Onlinebactrim no prescription