observe_field Location select (help b4 I go mad)

Based on your example, try this:

In your models (PS: I stripped the lu_ prefix on the class in my example so I explicitly reference the proper table based on your example):

class Country < ActiveRecord::Base   has_many :cities   def self.table_name() "lu_countries" end end

class City < ActiveRecord::Base   belongs_to :country   def self.table_name() "lu_cities" end end

In your controller, somewhere appropriate, populate @countries:

     @countries = Country.find(:all)

Also, add a new method to your controller to respond to the "observe_field" callback:

  def country_changed     @cities = Country.find(params[:country_id]).cities     render :partial => 'layouts/city_options', :layout => false   end

In your view:

    <select name="country_id" id="country_id">         <%= render(:partial => 'layouts/country_options', :layout => false) %>         <%= observe_field "country_id",              :url => {:controller => "YOUR_CONTROLLER", :action => "country_changed"},              :with => "country_id",              :update => "city_id" %>     </select>     <select name="city_id" id="city_id">     </select>

Create two partial views (I have them in the /layouts subdirectory):

_country_options.rhtml <%= options_from_collection_for_select(@countries, :id, :country) %>

_city_options.rhtml <%= options_from_collection_for_select(@cities, :id, :city) %>

The way I have it currently setup, the cities drop down will only be populated when you select a country. But you could set the country to a default for the user, populate the @cities variable as I'm doing in the country_changed method, and then render the city_options partial in the view.


Yes, absolutely. Hope it works for you...

Yes. Go ahead and populate @countries as I showed you but also set some variable to the id of the user's country like @user_country_id. Also, populate the @cities variable as well based on the users country like we were doing in the country_changed method. Then change _country_options.rhtml as follows:

<%= options_from_collection_for_select(@countries, :id, :country, selected_value = @user_country_id) %>

Or if you had a @user object that had the country_id you could code it as "selected_value = @user.country_id". The important thing is that it is the "id" of the country you need to specify in the selected_value parameter. Do something similar for the city.

Also, in my first example I wasn't populating the city drop down so you would need to do that in your view now as well:

    <select name="city_id" id="city_id">         <%= render(:partial => 'layouts/city_options', :layout => false) %>     </select>


Hi Scott,

To populate the cities list you need to add a line (2nd to the last line) to your "edit" method as follows:

   def edit      user = session[:user_id]      @profile = Profile.find(:first, :conditions => ["user_id = ?", user])      @countries = Country.find(:all)      @user_country_id = @profile.country_id      @cities = Country.find(@profile.country_id).cities      @user_city_id = @profile.city_id    end

Additionally, if you wanted to select the users city, you would need to set a variable like @user_city_id (see last line) and add ", selected_value = @user_city_id" to the _city_options.rhtml partial like we did with the countries.


Thats great! Now that I see your Profile class, there is one last thing you could do to simplify your code just a bit. Since you have the country_id and city_id available in the @profile variable, there really is no need to put them into the varaibles @user_country_id and @user_city_id. We can simply retrieve that data from the @profile variable when needed. So you could remove the following 2 lines from the "edit" method:

     @user_country_id = @profile.country_id      @user_city_id = @profile.city_id

And then replace @user_country_id with @profile.country_id in _country_options.rhtml and @user_city_id with @profile.city_id in _city_options.rhtml.


It fails for me in IE as well. What I had to do to get this to work was to wrap the <select> tag for city in a <div> and tell "observe_field" to update the div rather than the select. This means changing some stuff. First off, change your view from:

  <select name="profile[city_id]" id="profile_city_id" style="width: 200px">   <%= render(:partial => 'city_options', :layout => false) %>   </select>

to:   <div id="city_select_div">   <%= render(:partial => 'city_options', :layout => false) %>   </div>

Then change the _city_options partial to:

  <select name="profile[city_id]" id="profile_city_id" style="width: 200px">   <%= options_from_collection_for_select(@cities, :id, :city, selected_value = @user_city_id) %>   </select>

And finally, change the update parameter of "observe_field" from :update => "profile_city_id" to :update => "city_select_div".

That should take care of it. I am begining to come to the realization that ajax updates work better when the tag is wrapped in a div. Being a block level statement, I think it forces the browser to "work harder" when the DOM changes. I have yet to see someone make a blanket recommendation to this effect but I am starting to lean that way.