location - User/Address association in Rails -
i'm working on first rails project , i'm trying create proper user/address (or rather user/location) association. thought problem common , others had done i'm trying , easy find answer wasn't case. there many different questions extremely different answers , couldn't figure out how things in case. here's scenario:
the location can country, state/region or city, not more specific (i'm using google places library's autocomplete feature). avoid lot of duplicate information in users
table every time 1 or more users live in same city (country, state, city, latitude, longitude etc), figured should have locations
table. worse, user should have "home_location" , "current_location". associations:
has_one
at first thought: "well, user has address/location, should use has_one
association. turns out if use user has_one location
, location table 1 pointing user's table, not want, since many users should able reference same location.
belongs_to/has_many
"ok, i'll use belongs_to/has_many association" thought. seemed pretty neat @ first. seemed make lot of sense. i'm using nested forms gem, works pretty else i've done far, , nested form locations loaded , information sent correctly. location created , added database successfully, there 1 problem: user.location wasn't saved. trying figure out why, realize there's weird whole thing. rails not treating design structure way need (the way feel more intuitive). indeed, association used "user/microposts" (like in hartl's tutorial) , kind of thing. in case idea different. humans understand that, rails doesn't seem to. want user able lives in "edit profile" page. i've been reading seems rails expecting location's edit page have nested form users. it's expecting me create user this:
@location.user.create(:email=>"john@example.com")
while need create location this:
@user.location.create(:city=>"rio de janeiro", etc)
ok. maybe want specific , rail's standard association won't work. after code above create duplicate cities, i'd need like:
@user.location.find_or_create(:city=>"rio de janeiro")
(does exist associated objects?)
here's code attempt saved location didn't create association:
model
class user < activerecord::base attr_accessible ... :home_location, :home_location_attributes, :current_location, :current_location_attributes, etc belongs_to :home_location, :class_name => 'location' accepts_nested_attributes_for :home_location belongs_to :current_location, :class_name => 'location' accepts_nested_attributes_for :current_location ... end class location < activerecord::base attr_accessible :google_id, :latitude, :longitude, :administrative_area_level_1, :administrative_area_level_2, :city, :neighborhood, :country, :country_id belongs_to :country has_many :users end
schema
create_table "users", :force => true |t| ... t.integer "home_location" t.integer "current_location" t.text "about_me" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false ... end create_table "locations", :force => true |t| t.string "google_id", :null => false t.string "latitude", :null => false t.string "longitude", :null => false t.integer "country_id", :null => false t.string "administrative_area_level_1" t.string "administrative_area_level_2" t.string "city" t.string "neighborhood" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end
but seemed wanted particular gave , tried add form_for @location
. check in user controller if record existed , save in user's home_location attribute. removed following lines user model:
accepts_nested_attributes_for :home_location accepts_nested_attributes_for :current_location
and replaced f.fields_for
in edit_profile view form_for @location
.
then in controller added code deal location:
class userscontroller < applicationcontroller before_filter :signed_in_user, only: [:index, :edit, :update, :destroy] before_filter :signed_out_user, only: [:new, :create] before_filter :correct_user, only: [:edit, :update] ... def edit if @user.speaks.length == 0 @user.speaks.new end if @user.wants_to_learn.length == 0 @user.wants_to_learn.new end if @user.home_location.blank? @user.home_location = location.new end end def update logger.debug params ... @home_location = nil params[:home_location][:country_id] = params[:home_location].delete(:country) unless params[:home_location][:country_id].blank? params[:home_location][:country_id] = country.find_by_iso_3166_code(params[:home_location][:country_id]).id #@home_location = location.where(params[:home_location]) #the line above describe behavior want, #but testing purposes simplified below: @home_location = location.find(2) #there location id=2 in db if @home_location.nil? @home_location = location.new(params[:home_location]) if !@home_location.save @home_location = nil end end end if @user.update_attributes(params[:user]) @user.home_location = @home_location @user.save flash[:success] = "profile updated" sign_in @user #render :action => :edit redirect_to :action => :edit else render :action => :edit end end ... end
but still doesn't save association. in fact in console, no matter do, user's home_location attribute never gets saved database.
does have idea of may happening??
why association not being saved? what's correct way of doing in rails?
i'm sorry length of question. hope reads it. i'd grateful!
thanks
edit 1
following robheaton's tip, added custom setter in user model:
def home_location= location #params[:user][:home_location] locations = location.where(location) @home_location = locations.first.id unless locations.empty? end
after fixing issues popped up, started working! data saved database. still have no idea why didn't work in controller though. body have guess? i'm wondering if mistake wasn't somewhere else , ended fixing without noticing because code better organized in model.
still, problem not solved. although value saved database, can't access associated model in standard rails way.
1.9.3p362 :001 > ariel = user.first user load (0.5ms) select "users".* "users" limit 1 => #<user id: 1, first_name: "ariel", last_name: "pontes", username: nil, email: "pontes@ariel.com", password_digest: "$2a$10$ue8dh/nrh9kl9lud8jjqu.okd6tte i4h1tphmroniq15...", remember_token: "kadybxrh1g0x-be_hxha4w", date_of_birth: nil, gender: nil, interested_in: 0, relationship_status: nil, home_location: 3, curr ent_location: nil, about_me: "", created_at: "2013-05-07 14:28:05", updated_at: "2013-05-09 20:10:41", home_details: nil, current_details: nil> 1.9.3p362 :002 > ariel.home_location => nil
the weird thing not isn't rails able return associated object, won't return integer id stored in object! how make sense? hoping location object and, worst case scenario, expecting 3 in return. instead nil.
i tried write custom getter anyway:
def home_location if @home_location.blank? return nil end location.find(@home_location) end
but of course doesn't work. more ideas??
something like:
class user < activerecord::base def location= city_name write_attribute :location, location.find_by_city_name(city_name) end end
should it. can define state=
, city=
, on , in each case find appropriate column. general principle want of logic out of controllers possible. writing 10+ lines of code process incoming params want consider whether can in model.
Comments
Post a Comment