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.

-Paul

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>

-Paul

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.

-Paul

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.

-Paul

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.

-Paul