1

I am currently reading A Guide to Active Record Associations.

I get that you choose between has_one or belong_to depending on how you'd like to lay out the association.

But I am not entirely clear if there is difference between the following.

  1. Declare X has_one Y or Y belong_to X
  2. Declare X has_one Y AND Y belong_to X

So is there any case where you have to explicitly say X has_one Y and Y belong_to X ? Or is it always sufficient to say either X has_one Y or Y belong_to X.

Jason Kim
  • 18,102
  • 13
  • 66
  • 105

2 Answers2

3

You don't have to, it just depends on your needs.

All the methods do is add additional methods/metadata to the class they're used in: if you don't want/need those methods, there's no requirement to add them.

The methods added are in the details section.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
  • But what happens when you just use one of them. Can you call X.Y and Y.X still? – John Nov 22 '11 at 05:53
  • 2
    @John No; each method adds the methods to the class its used in--not the referenced class. – Dave Newton Nov 22 '11 at 05:54
  • I see. Is there any significance to the foreign key being in the table which declares 'belongs_to'? – John Nov 22 '11 at 05:56
  • @John Significant in what way? The fkey is what makes that object "belong to" the table the fkey refers to, is that what you mean? – Dave Newton Nov 22 '11 at 05:59
  • If X has_one Y, how can the has_one methods work without there being a foreign key in Y model? – John Nov 22 '11 at 06:02
  • @John Er, [there is](http://guides.rubyonrails.org/association_basics.html#the-has_one-association). – Dave Newton Nov 22 '11 at 06:05
  • Without the foreign key, seems like there would be no connection. The model with the has_one declared might have the methods, but what good are they if not connected to anything? – John Nov 22 '11 at 06:25
  • @John Perhaps you should look at the methods. – Dave Newton Nov 22 '11 at 06:26
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/5221/discussion-between-john-and-d-n) – John Nov 22 '11 at 06:31
2

has_many: Adds the methods for retrieval and query of collections of associated object.

belongs_to: Adds the methods for retrieval and query of single associated object for which this object holds an id

so, if you dont require to use methods on both the associated objects you may choose not the set the association accordingly.But its mandatory to put the foreign key in the model where the one instance is associated to one and only one instance of the other object that is: 'belongs_to' model.

Explaination:

lets consider schema like:

create_table "cars", :force => true do |t|
t.integer  "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end

create_table "users", :force => true do |t|
t.datetime "created_at"
t.datetime "updated_at"
end

and models as:

class User < ActiveRecord::Base
end

class Car < ActiveRecord::Base
belongs_to :user
end

the result is:

D:\temp>rails c
Loading development environment (Rails 3.0.10)
irb(main):001:0> U = User.first
=> #<User id: 1, created_at: "2011-11-22 06:43:04", updated_at: "2011-11-22 06:43:04">

irb(main):002:0> C = Car.first
=> #<Car id: 1, user_id: 1, created_at: "2011-11-22 06:43:34", updated_at: "2011-11-22 06:43:34">
irb(main):003:0> C.user
=> #<User id: 1, created_at: "2011-11-22 06:43:04", updated_at: "2011-11-22 06:43:04">
irb(main):004:0> U.cars
NoMethodError: undefined method `cars' for #<User:0x3d19970>
from C:/Ruby/lib/ruby/gems/1.9.1/gems/activemodel-3.0.10/lib/active_model/attribute_methods.rb:392:in `method_missing'
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.10/lib/active_record/attribute_methods.rb:46:in `method_missing'
    from (irb):4
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'
irb(main):005:0> exit

And if the models are like below:

and models as:

class User < ActiveRecord::Base
has_many :cars
end

class Car < ActiveRecord::Base
end

Result is:

D:\temp>rails c
Loading development environment (Rails 3.0.10)
irb(main):001:0> U = User.first
=> #<User id: 1, created_at: "2011-11-22 06:43:04", updated_at: "2011-11-22 06:43:04">
irb(main):002:0> C = Car.first
=> #<Car id: 1, user_id: 1, created_at: "2011-11-22 06:43:34", updated_at: "2011-11-22 06:43:34">
irb(main):003:0> U.cars
=> [#<Car id: 1, user_id: 1, created_at: "2011-11-22 06:43:34", updated_at: "2011-11-22 06:43:34">]
irb(main):004:0> C.user
NoMethodError: undefined method `user' for #<Car:0x41524c8>
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/activemodel-3.0.10/lib/active_model/attribute_methods.rb:392:in `method_missing'
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.10/lib/active_record/attribute_methods.rb:46:in `method_missing'
    from (irb):4
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'
    from C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'
irb(main):005:0>
riddhi_agrawal
  • 215
  • 2
  • 8