fernandohur
fernandohur

Reputation: 7144

Creating a many-to-many relation in Rails

So I'm Rails n00b and I want to create a "favorites" relationship such that a User can have many favorite Item. I'm not entirely sure how to do this, this is how I'm going to try but I'm not sure if this is a good practice at all:

class User < ActiveRecord::Base
 has_many :favorites
 //other code
end

class Favorite < ActiveRecord::Base
 belong_to :user
 has_one :item
end

class Item < ActiveRecord::Base
 belongs_to :item
end

Is this a good way to do it? Should I be using has_and_belongs_to_many ? I'm specially concerned in the following scenario: Say a user has 100 favorite items. When I do a User.find(id) will I also be retrieving the 100 favorites and the 100 Items?

In case it's important: ruby version 1.9.3, rails version 3.2.11

Upvotes: 0

Views: 174

Answers (3)

Peter de Ridder
Peter de Ridder

Reputation: 2399

In your case has_many :through is definitely the way to go. I would recommend reading: http://guides.rubyonrails.org/association_basics.html

Of particular interest with regard to your question:

2.8 Choosing Between has_many :through and has_and_belongs_to_many

Rails offers two different ways to declare a many-to-many relationship between models. The simpler way is to use has_and_belongs_to_many, which allows you to make the association directly:

class Assembly < ActiveRecord::Base
  has_and_belongs_to_many :parts
end

class Part < ActiveRecord::Base
  has_and_belongs_to_many :assemblies
end

The second way to declare a many-to-many relationship is to use has_many :through. This makes the association indirectly, through a join model:

class Assembly < ActiveRecord::Base
  has_many :manifests
  has_many :parts, :through => :manifests
end

class Manifest < ActiveRecord::Base
  belongs_to :assembly
  belongs_to :part
end

class Part < ActiveRecord::Base
  has_many :manifests
  has_many :assemblies, :through => :manifests
end

The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you’ll need to remember to create the joining table in the database).

You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.

Upvotes: 2

JazzJackrabbit
JazzJackrabbit

Reputation: 515

It is better than using has_and_belongs_to_many.

When I do a User.find(id) will I also be retrieving the 100 favorites and the 100 Items?

No. You'll just get the user object.

Update: Calling User.include(:favourites, :items).find(id) will get you joined tables in case you want to make many calls to items table from user object.

Upvotes: 0

catsby
catsby

Reputation: 11342

Can you try has_many => :through?

class User < ActiveRecord::Base
 has_many :favorites
 has_many :items, :through => :favorites
 //other code
end

Upvotes: 3

Related Questions