views:

35

answers:

3

In my application I have 2 classes like this:

class City < ActiveRecord::Base
  has_many :events
end

class Event < ActiveRecord::Base
  belongs_to :city
  attr_accessible :title, :city_id
end

If I create city object:

city = City.create!(:name => 'My city')

and then pass parameters to create event like this:

event = Event.create!(:name => 'Some event', :city => city)

I get

event.city_id => null

So the question is - is it possible to pass parameters in such a way to get my objects connected, what am I doing wrong? Or should I use other ways (like

event.city = city

) ?

A: 

You should be doing

event = Event.create!(:name => 'Some event', :city_id => city.id)
neutrino
I know, that I can do it this way. I'm asking if it is possible to pass parameters as I described.
LightAlloy
well, your models don't get saved - probably validation fails on city being blank - do you want more proofs that it couldn't work? :)
neutrino
Sorry, I made a mistake in my question :( I meant "event.city_id", not "event.id". Objects are saved, but they are not connected.
LightAlloy
`create!` would raise an exception if validation fails
mikej
@mikej, good point, forgot about that@LightAlloy, your objects aren't connected because there's no such thing as `city` in your `Event`'s attributes hash, there's only `city_id`. To get your objects connected you should fill `city_id` which is not happening in your case - you're effectively assigning `city.id` to an inexistent `city` attribute.
neutrino
@neutrino you're wrong that `City.new` (or its brethren `build` and `create`) won't understand the `:city` key. As long as `Event.belongs_to :city` or `Event.has_one :city` (the former is true in this case) *and* `:city` is not a protected attribute (by inclusion in `attr_protected` or exclusion from `attr_accessible`), `City` is perfectly happy with translating that key into an `id` and will even cache the instance so it doesn't do a lookup the next time you request `my_event.city`.
James A. Rosen
Actually there is attr_accessible line in my class.It is like attr_accessible :name, :city_idDoesn't city_id in this list allow me to pass both city and city_id parameters?
LightAlloy
@LightAlloy: aha :) No, `attr_accessible` is *very* strict. Setting `city_id` to accessible does *not* confer privileges to the corresponding `city`. You can simply add `city` to the list, but you probably want to *replace* `city_id` with `city`... *unless* you have a `<form>` with a `<select>` of cities to choose from, in which case the controller's call to `update` will probably pass a `city_id` rather than a `City` instance. In that case, you'd want both in the `attr_accessible` list.
James A. Rosen
thanx, accepted.
LightAlloy
A: 

This will work:

city = City.create!(:name => "London")

event = Event.create!(:name => "Big Event")
event.city = city
event.save

Alternatively, if Event.validates_presence_of :city, and thus the Event.create! call will fail without a City, you could do this:

event = Event.new(:name => 'Big Event').tap do |e|
  e.city = city
  e.save!
end
thomasfedb
That's a strange method, I would do `city = City.create!(:name => "London")``event = Event.new(:name => "Big Event")``event.city = city``event.save!`insteadBut, anyway, my question was not about it.
LightAlloy
+2  A: 

Generally this happens when you have an attr_accessor that excludes or an attr_protected that includes the :city attribute on Event. Allowing :city_id to be accessible does not automatically allow :city to be so.

(NB: this answer provided as per the discussion in comments above, and thus community-wiki.)

James A. Rosen