Why does belongs_to handle "conflicts" this way?

When you define belongs_to in a model, you can either access
association or association_id. I was wondering how Rails would handle
things if you set each one to be different.

I made two simple models:

class Foo < ActiveRecord::Base; end
class Bar < ActiveRecord::Base
belongs_to :foo
end

Now here’s a script/console session.

f = Foo.create
=> #<Foo:0x270ec10 @attributes={“name”=>nil, “id”=>1},
@new_record=false, @errors=#<ActiveRecord::Errors:0x269fd10
@base=#<Foo:0x270ec10 …>, @errors={}>>

b = Bar.new
=> #<Bar:0x26989d4 @attributes={“foo_id”=>nil}, @new_record=true>

b.foo_id = 10
=> 10

b.foo = f
=> #<Foo:0x270ec10 @attributes={“name”=>nil, “id”=>1},
@new_record=false, @errors=#<ActiveRecord::Errors:0x269fd10
@base=#<Foo:0x270ec10 …>, @errors={}>>

b.save
b=> true

b.reload
=> #<Bar:0x26989d4 @attributes={“foo_id”=>“1”, “id”=>“1”},
@new_record=false, @errors=#<ActiveRecord::Errors:0x268bcfc
@base=#<Bar:0x26989d4 …>, @errors={}>, @foo=nil>

Okay, that’s fair. I set foo after foo_id, so it makes sense that it
replaces foo_id, nothing strange there.

b = Bar.new
=> #<Bar:0x261bb78 @attributes={“foo_id”=>nil}, @new_record=true>

b.foo = f
=> #<Foo:0x270ec10 @attributes={“name”=>nil, “id”=>1},
@new_record=false, @errors=#<ActiveRecord::Errors:0x269fd10
@base=#<Foo:0x270ec10 …>, @errors={}>>

b.foo_id = 5
=> 5

b.save
b=> true

b.reload
=> #<Bar:0x261bb78 @attributes={“foo_id”=>“1”, “id”=>“3”},
@new_record=false, @errors=#<ActiveRecord::Errors:0x2613ef0
@base=#<Bar:0x261bb78 …>, @errors={}>, @foo=nil>

Hrm. I set foo_id after I set foo, but it still uses the associated
object’s id, rather than the explicit id. Maybe it looks to see if
there’s an associated object, and if so use that? Well let’s test it
on an an object restored from the db, since that would already have an
associated foo.

b = Bar.find :first
=> #<Bar:0x2604bd0 @attributes={“foo_id”=>“1”, “id”=>“1”}>

b.foo_id = 5
=> 5

b.save
b=> true

b.reload
=> #<Bar:0x2604bd0 @attributes={“foo_id”=>“5”, “id”=>“1”},
@errors=#<ActiveRecord::Errors:0x25fd09c @base=#<Bar:0x2604bd0 …>,
@errors={}>, @foo=nil>

Okay well here we didn’t get the foo object, so I guess that’s why.
We’ll include it.

b = Bar.find 3, :include => :foo
=> #<Bar:0x25bb084 @attributes={“foo_id”=>“1”, “id”=>“3”},
@foo=#<Foo:0x25baeb8 @attributes={“name”=>nil, “id”=>“1”}>>

b.foo.id
=> 1

b.foo_id = 5
=> 5

b.save
=> true

b.reload
=> #<Bar:0x25bb084 @attributes={“foo_id”=>“5”, “id”=>“3”},
@errors=#<ActiveRecord::Errors:0x25b3f64 @base=#<Bar:0x25bb084 …>,
@errors={}>, @foo=nil>

So the conclusion I’ve come to is that if I set both the association
and the association_id, it uses the id from the associated object. If
I set only the association_id, it’ll use that even if there’s already
an associated object. I’ve looked through the source and haven’t been
able to figure out how it does that. I’d also like to know why it
works that way.

Pat

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs