rails question: dynamic selection drop-down menu

25 views
Skip to first unread message

Chase Southard

unread,
Mar 12, 2008, 2:17:06 PM3/12/08
to ky...@googlegroups.com
Hi All,

I'm probably making this way too complicated. I know that everything I have in mind here is possible, but I can't seem to figure this out. Clearly, I've put Rails down for far too long. I've looked around for a solution on railsforum and rails-talk, but to no avail. I think that only made matters worse.

Ignoring the bigger picture for a moment, I'd like to present the user with two drop-down menus of constant options. The first menu is a list of States. The second menu is a list of USGS water monitoring stations. I'd like to have two ajax-esque actions. I'm currently stuck on the first (although, i haven't really worked on the second. I'm sure I'll get stuck there too). (For the second action, more of the same. Update the page with the parsed and presented real-time data from the station upon station selection.)

When the user selects a state from the state menu, I'd like the station menu to update with just the list of the stations in that state. Sounds relatively straight forward. What combination of js, controller actions, and voodoo will make this work? I've tried more than a few.

My understanding: I think I should have a form where the selection :onchange invokes an Ajax.Updater action. This action should pass the state_id to a controller action that will make a new @stations to then update the the station select collection. I think this is a GET action.

What I have:
Rails 2.0
Routes: standard
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
  **I have not set map.resources**
Two models: 1) States {name, abbrev}; 2) Stations {sitename, siteno, state_id} (stations is ~4000 rows)
Associations: states have_many :stations; station belongs_to :state

#controller
class WaterController < ApplicationController
  def index
    @states = State.find(:all).sort_by{|s| s.name }
    @stations = Station.find(:all).sort_by{|t| t.state.name}
    #@stations = []
    respond_to do |format|
      format.html
    end
  end

  def update_sites
    @stations = Station.state.find(params[:id]).sort_by{|n| n.sitename}
   
  end
end

#view
#index.html.erb
<% form_for :water do |f| %>
    <%= f.collection_select(:state_id, @states, :id, :name, {:prompt => "Select a state"}, {:onchange => 'updateSites();'} )%>
    <%= f.collection_select(:station_id, @stations, :siteno, :sitename, :prompt => "Select a station") %>
   
<% end %>

#application.js
 updateSites = function(){
    new Ajax.Updater ('water_station_id',
                    'update_sites/'+this[this.selectedIndex].value,
                    {asynchronous:true, evalScripts:true, parameters:'authenticity_token='+encodeURIComponent('"+form_authenticity_token.to_s+"')});
}


I appreciate any thoughts on where I have gone wrong.

I thought that this would be a quick and easy project to get working and actually deploy (which is something that I have not done, as localhost doesn't count).

If you think that you'd like to help (it's obvious that I could use some help), I'll send you an even lengthier email with my ideas of what I'd like to accomplish.

Again, thanks.

Chase

Todd

unread,
Mar 12, 2008, 11:06:24 PM3/12/08
to Kentucky Ruby user group
Order the "Flexible Rails" book and do your UI with Flex and services
with Rails, then I can help you.

;-)

- Todd

chaserx

unread,
Mar 12, 2008, 11:12:26 PM3/12/08
to Kentucky Ruby user group
this still doesn't work properly, but perhaps it's a step closer. at
least it registers that a state is selected.
output:
Processing WaterController#populate_second_pulldown (for 127.0.0.1 at
2008-03-12 22:44:14) [POST]
Session ID:
BAh7BzoMY3NyZl9pZCIlOGViNGNhNmQ4ZGFhN2VkM2E0MTRmYmYyOTJhNmYy
%0ANTEiCmZsYXNoSUM6J0FjdGlvbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhh
%0Ac2h7AAY6CkB1c2VkewA%3D--fa4c764d344d999cae70f4e7c89e530cc758b57b
Parameters:
{"authenticity_token"=>"c1f61ba566bff49f33ca095aca8003cd9020be3a",
"action"=>"populate_second_pulldown", "controller"=>"water",
"363096583"=>nil}
Station Load (0.008807) SELECT * FROM `stations` WHERE
(`stations`.`state_id` IS NULL)
Rendering template within layouts/water

#view
#index.html.erb
<% form_for :water do |f| %>
<%= f.collection_select(:state, @states, :id, :name, {:prompt =>
"Select a state"} )%>
<%= f.collection_select(:station,
@stations, :siteno, :sitename, :prompt => "Select a station") %>

<%= observe_field "water_state", :update => "water_station", :url =>
{:action => 'populate_second_pulldown'} %>
<% end %>

#water controller
class WaterController < ApplicationController
def index
@states = State.find(:all).sort_by{|s| s.name }
@stations = Station.find(:all).sort_by{|t| t.state.name}
#@stations = []
respond_to do |format|
format.html
end
end

def populate_second_pulldown
@stations = Station.find(:all, :conditions => {:state_id =>
params[:id]})
#log shows massive errors here as a /populate_second_pullodwn/
viewl is expected.
#ActionController::MissingTemplate (Missing template water/
populate_second_pulldown.html.erb in view path ....
end
end



On Mar 12, 2:17 pm, "Chase Southard" <chase.south...@gmail.com> wrote:

chaserx

unread,
Mar 12, 2008, 11:39:21 PM3/12/08
to Kentucky Ruby user group
more progress.

using :with => "'state_id=' + value" in observe_field will send the
param correctly. controller method updated as well with :state_id in
the conditions

<%= observe_field "water_state", :update => "water_station", :url =>
{:action => 'populate_second_pulldown'}, :with => "'state_id=' +
value" %>

Parameters:
{"authenticity_token"=>"c1f61ba566bff49f33ca095aca8003cd9020be3a",
"action"=>"populate_second_pulldown", "controller"=>"water",
"state_id"=>"1028962928"}
Station Load (0.009435) SELECT * FROM `stations` WHERE
(`stations`.`state_id` = '1028962928')

However, the select drop down is updated visually to null/blank/
empty.

Rendering template within layouts/water
ActionController::MissingTemplate....yada...yada...

chaserx

unread,
Mar 14, 2008, 10:27:51 AM3/14/08
to Kentucky Ruby user group
even more progress. probably not ideal, but it does what I expect. I
had to split the form in two. And render a partial for the second
list.

#index.html.erb
<% form_for :water do |f| %>
<div><%= f.collection_select(:state, @states, :id, :name, {:prompt =>
"Select a state"} )%></div>

<%= observe_field "water_state", :update => "secondList", :url =>
{:action => 'populate_second_pulldown'}, :with => "'state_id=' +
value" %>
<% end %>
<div id="secondList">

</div>

#water_controller
class WaterController < ApplicationController
def index
@states = State.find(:all).sort_by{|s| s.name }
#@stations = Station.find(:all).sort_by{|t| t.state.name}
#@stations = []
respond_to do |format|
format.html
end
end

def populate_second_pulldown
@stations = Station.find(:all, :conditions => {:state_id =>
params[:state_id]})
render :partial => "secondList"
end
end

#_secondList partial
<% form_for :water do |g| %>
<%= g.collection_select(:station,
@stations, :siteno, :sitename, :prompt => "Select a station") %>
<% end %>

Reply all
Reply to author
Forward
0 new messages