Topic: Many to One with a Relationship back to a Special One (from a newbie)

I have a problem I'm not quite sure how to solve. I've pared it down to the simplest thing I can and I still don't see what's happening.

I have two models Owners and Things. The Owners can own many Things, but they also have one Thing that is their favorite. The criteria for finding the favorite Thing is pretty ugly, so I thought the best thing would be for each Owner to be able to have a relationship to its favorite Thing.

owner.rb says:

class Owner < ActiveRecord::Base

  has_many :things
  belongs_to :favorite_thing, {:class_name => "Thing"}

end

thing.rb says:

class Thing < ActiveRecord::Base

  belongs_to :owner

end

and the migration that created them says this:

class CreateFavorites < ActiveRecord::Migration
  def self.up
    create_table :owners, :options => 'ENGINE=InnoDb DEFAULT CHARSET=utf8' do |t|
      t.column :favorite_thing_id,            :integer,   :null => false
    end

    create_table :things, :options => 'ENGINE=InnoDb DEFAULT CHARSET=utf8' do |t|
      t.column :owner_id,            :integer,   :null => false
    end
  end

  def self.down
    drop_table :owners
    drop_table :things
  end

end

If I start a console session, here's what happens:

Loading development environment.
>> o = Owner.new
=> #<Owner:0x3b16d18 @attributes={"favorite_thing"=>0}, @new_record=true>
>> o.save
=> true
>> t1 = Thing.new
=> #<Thing:0x3aae528 @attributes={"owner_id"=>0}, @new_record=true>
>> t1.owner = o
=> #<Owner:0x3b16d18 @attributes={"favorite_thing"=>0, "id"=>1}, @new_record_bef
ore_save=true, @new_record=false, @errors=#<ActiveRecord::Errors:0x3aba5d0 @base
=#<Owner:0x3b16d18 ...>, @errors={}>>
>> t1.save
=> true
>> t2 = Thing.new
=> #<Thing:0x3a995a0 @attributes={"owner_id"=>0}, @new_record=true>
>> t2.owner = o
=> #<Owner:0x3b16d18 @attributes={"favorite_thing"=>0, "id"=>1}, @new_record_bef
ore_save=true, @new_record=false, @errors=#<ActiveRecord::Errors:0x3aba5d0 @base
=#<Owner:0x3b16d18 ...>, @errors={}>>
>> t2.save
=> true
>> o.favorite_thing = t2
=> #<Thing:0x3a995a0 @attributes={"id"=>2, "owner_id"=>1}, @new_record=false, @e
rrors=#<ActiveRecord::Errors:0x3a90d38 @base=#<Thing:0x3a995a0 ...>, @errors={}>
, @owner=#<Owner:0x3b16d18 @attributes={"favorite_thing"=>#<Thing:0x3a995a0 ...>
, "id"=>1}, @new_record_before_save=true, @new_record=false, @errors=#<ActiveRec
ord::Errors:0x3aba5d0 @base=#<Owner:0x3b16d18 ...>, @errors={}>>>
>> o.save
=> true
>> o.favorite_thing = t1
=> #<Thing:0x3aae528 @attributes={"id"=>1, "owner_id"=>1}, @new_record=false, @e
rrors=#<ActiveRecord::Errors:0x3aa00f8 @base=#<Thing:0x3aae528 ...>, @errors={}>
, @owner=#<Owner:0x3b16d18 @attributes={"favorite_thing"=>#<Thing:0x3aae528 ...>
, "id"=>1}, @new_record_before_save=false, @new_record=false, @errors=#<ActiveRe
cord::Errors:0x3aba5d0 @base=#<Owner:0x3b16d18 ...>, @errors={}>>>
>> o.save
=> true
>> Owner.find(1)
=> #<Owner:0x3a711d8 @attributes={"favorite_thing"=>"1", "id"=>"1"}>
>> [b]Owner.find(1).favorite_thing[b]
=> 1
>>

So then I thought maybe the Owner was supposed to have a member called favorite_thing_id instead, but that still doesn't work. Am I going down the wrong path completely, missing something obvious or just totally fouled up in my approach?

Thanks in advance for any assistance you can provide.

Re: Many to One with a Relationship back to a Special One (from a newbie)

Meant to say (in the next-to-last paragraph)

"So then I thought maybe the Owner was supposed to have a member called favorite_thing instead of favorite_thing_id ..."

Re: Many to One with a Relationship back to a Special One (from a newbie)

hmm..

if each owner has only one favorite thing, why dont you just mark the favorite?

I.E.

Owner -> Jake
Things -> Car, Computer, Monitor, Mixer, Mouse, Lighter

Things Jake Owns -> car, computer, monitor
Jakes Favorite Thing -> Computer

Cant you just add a column to Owners called favorite_id, which holds the ID of the thing that is their favorite?

then you can add a method to Owners like so

class Owner < ActiveRecord::Base
  has_many :things

  def favorite_thing
    things.find(favorite_id)
  end
end

So to find the favorite of @owner, you would just call @owner.favorite  which would return an object of type Thing

hope that helps

--jake

---------------------------------------------------------------------
Rails Development - Agile rails consulting and development for startups on a budget
Flvorful Blog - Some ramblings
Flvorful's Open Source Projects - Some handy hacks for your rails projects.

Re: Many to One with a Relationship back to a Special One (from a newbie)

That works for me. I guess I was caught up in the magic of ActiveRecord and thought there would be some magic way to do this. Thanks.

Re: Many to One with a Relationship back to a Special One (from a newbie)

bobf wrote:

That works for me. I guess I was caught up in the magic of ActiveRecord and thought there would be some magic way to do this. Thanks.

oh yea, i did that too when i first started.  Then i realized that i dont need ALL the magic at the same time.


peace

--jake

---------------------------------------------------------------------
Rails Development - Agile rails consulting and development for startups on a budget
Flvorful Blog - Some ramblings
Flvorful's Open Source Projects - Some handy hacks for your rails projects.