سؤال

I getting troubles with a self referential table.

I got an orb model which can hold planets, stars and moons. I want to tell that one thing "orbit" another

i look at the rails guide, but i coulnd get it working

My model:

class Orb < ActiveRecord::Base
  belongs_to :orb_type
  has_and_belongs_to_many :books

  belongs_to :orbit, :class_name => "Orb"
  has_many :orbs, :class_name => "Orb", :foreign_key => "orb_id"

  attr_accessible :descr, :nome, :orb_type_id, :book_ids, :orb_id

  validates :nome, uniqueness: true, presence: true
end

I think i am using bad relations names (maybe in the wrong way around)

1.9.3-p448 :002 > earth = Orb.find(1)
  Orb Load (0.2ms)  SELECT "orbs".* FROM "orbs" WHERE "orbs"."id" = ? LIMIT 1  [["id", 1]]
 => #<Orb id: 1, nome: "Terra", descr: "123123", orb_type_id: 1, created_at: "2013-09-25 14:53:35", updated_at: "2013-09-25 14:57:40", orb_id: nil> 
1.9.3-p448 :003 > moon = Orb.find(2)
  Orb Load (0.2ms)  SELECT "orbs".* FROM "orbs" WHERE "orbs"."id" = ? LIMIT 1  [["id", 2]]
 => #<Orb id: 2, nome: "Lua", descr: "asd", orb_type_id: 2, created_at: "2013-09-25 14:53:46", updated_at: "2013-09-25 14:55:31", orb_id: nil> 
1.9.3-p448 :004 > sun = Orb.find(3)
  Orb Load (0.2ms)  SELECT "orbs".* FROM "orbs" WHERE "orbs"."id" = ? LIMIT 1  [["id", 3]]
 => #<Orb id: 3, nome: "Sol", descr: "asd", orb_type_id: 3, created_at: "2013-09-25 14:53:55", updated_at: "2013-09-25 14:53:55", orb_id: nil> 
1.9.3-p448 :006 > moon.orbit=earth
 => #<Orb id: 1, nome: "Terra", descr: "123123", orb_type_id: 1, created_at: "2013-09-25 14:53:35", updated_at: "2013-09-25 14:57:40", orb_id: nil> 
1.9.3-p448 :007 > earth.orbit=sun
 => #<Orb id: 3, nome: "Sol", descr: "asd", orb_type_id: 3, created_at: "2013-09-25 14:53:55", updated_at: "2013-09-25 14:53:55", orb_id: nil> 
1.9.3-p448 :008 > earth
 => #<Orb id: 1, nome: "Terra", descr: "123123", orb_type_id: 1, created_at: "2013-09-25 14:53:35", updated_at: "2013-09-25 14:57:40", orb_id: nil> 
1.9.3-p448 :009 > sun
 => #<Orb id: 3, nome: "Sol", descr: "asd", orb_type_id: 3, created_at: "2013-09-25 14:53:55", updated_at: "2013-09-25 14:53:55", orb_id: nil> 
1.9.3-p448 :010 > moon
 => #<Orb id: 2, nome: "Lua", descr: "asd", orb_type_id: 2, created_at: "2013-09-25 14:53:46", updated_at: "2013-09-25 14:55:31", orb_id: nil> 

in the end nothing get associated, the FK still nill.

The collun orb_id was added latter on the model. I setup a migration and added it in the model. I don't think it could be related to my problem...


EDIT:

Now everything is even odd. i change my model to:

class Orb < ActiveRecord::Base
  belongs_to :orb_type
  has_and_belongs_to_many :books

  belongs_to :orbit, :class_name => "Orb"
  has_many :orbits, :class_name => "Orb", :foreign_key => "orb_id"

  attr_accessible :descr, :nome, :orb_type_id, :book_ids, :orb_id

  validates :nome, uniqueness: true, presence: true
end

In rails console (rails c) i try:

1.9.3-p448 :008 > earth = Orb.find(1)
  Orb Load (0.2ms)  SELECT "orbs".* FROM "orbs" WHERE "orbs"."id" = ? LIMIT 1  [["id", 1]]
 => #<Orb id: 1, nome: "Terra", descr: "", orb_type_id: 1, created_at: "2013-09-25 17:51:26", updated_at: "2013-09-25 18:16:58", orb_id: 3> 
1.9.3-p448 :009 > earth.orbit
 => nil 
1.9.3-p448 :010 > earth.orbits
  Orb Load (0.3ms)  SELECT "orbs".* FROM "orbs" WHERE "orbs"."orb_id" = 1
 => [#<Orb id: 2, nome: "Lua", descr: "", orb_type_id: 2, created_at: "2013-09-25 17:51:40", updated_at: "2013-09-25 18:17:31", orb_id: 1>] 
1.9.3-p448 :011 > 

What the heck? orbits seen to return what i want, but it i try to use it:

1.9.3-p448 :004 > earth.orbits.nome
NoMethodError:   Orb Load (0.4ms)  SELECT "orbs".* FROM "orbs" WHERE "orbs"."orb_id" = 1
undefined method `nome' for #<ActiveRecord::Relation:0x00000003d593c0>
        from /usr/local/rvm/gems/ruby-1.9.3-p448/gems/activerecord-3.2.12/lib/active_record/relation/delegation.rb:45:in `method_missing'
        from /usr/local/rvm/gems/ruby-1.9.3-p448/gems/activerecord-3.2.12/lib/active_record/associations/collection_proxy.rb:100:in `method_missing'
        from (irb):4
        from /usr/local/rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.12/lib/rails/commands/console.rb:47:in `start'
        from /usr/local/rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.12/lib/rails/commands/console.rb:8:in `start'
        from /usr/local/rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.12/lib/rails/commands.rb:41:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'
هل كانت مفيدة؟

المحلول 2

i figure it out. I should make the rom in the table withe the name of relation (orbit_id) instead of doing it the table name (orb_id)

Fixing that everything started to work nicely :)

has_many :orbters, class_name: "Orb", foreign_key: "orbit_id"
belongs_to :orbit, class_name: "Orb"

نصائح أخرى

Technically, it's not great that you have planets, stars, and moons all within the same model. They all behave differently and should each warrant their own model. E.g. a star will never orbit a planet, and a planet will never orbit a moon (by definition). By structuring your database the way you have, you're setting yourself up for corrupted data, which will always happen if you allow it to.

If you must have them all within the Orb model, I would recommend 2 models: 1 for the Orbs (stars, planets, moons), and 1 for the Orbits. The Orbit class would essentially be a table like so:

Orbit model:

| id | orbited_id | orbiter_id |
--------------------------------
|  0 | planet_id  | moon_id    |
|  1 | star_id    | planet_id  |
|  2 | planet_id  | moon_id    |
| ...| etc        | etc        |

And then you can set up the association in orb.rb:

has_and_belongs_to_many :orbits,
                        class_name: 'Orb',
                        join_table: :orbits,
                        foreign_key: :orbited_id,
                        association_foreign_key: :orbiter_id,
                        uniq: true

This will allow you to do things like

>> sun = Orb.find(1)
>> sun.orbits
=> [ <Orb mercury>, <Orb venus>, ..., <Orb pluto> ]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top