Newbie question, beware! I'd like to implement a basic many-to-many relationship in Rails and I'm trying to find out which approach is considered the most "rails way" of them. In a traditional non-ActiveRecord DB I'd just created two tables and a junction table and written a bunch of logic to make sure all three tables are taken in consideration when operations are performed on any of them.
This is my first time using an ORM and so I'm trying to find out if perhaps ActiveRecord somehow simplifies the process for you, perhaps by not requiring a junction table to be manually created.
Railscasts seems like a reputable source of Rails wisdom, are the two ways in this cast truly "Rails way" or can I do better? - http://railscasts.com/episodes/47-two-many-to-many
There's basically two ways: has_and_belongs_to_many
(habtm
) and has_many
with a :through option that points to another association. Both require join tables; the latter is what we call a join model, because you typically add more information to the join.
For example, consider an application with a User model who bookmarks Sites. One way would be to implement it as a habtm
relationship
class User < ActiveRecord::Base
has_and_belongs_to_many :sites
end
class Site < ActiveRecord::Base
has_and_belongs_to_many :users
end
user.sites << Site.find(...)
This modeling will also require creating the sites_users
table, which necessarily will lack a primary key.
The problem with this is you're likely to want to store additional information on it, so you might as well go with a join model, in this case Bookmark:
class User < ActiveRecord::Base
has_many :bookmarks
has_many :sites, :through => :bookmarks
end
class Site < ActiveRecord::Base
has_many :bookmarks
has_many :users, :through => :bookmarks
#edit: adding validation for requiring at least one bookmark
validate_before_create :at_least_one_bookmark
private
def at_least_one_bookmark
errors.add_to_base("requires at least one bookmark") unless bookmarks.count > 0
end
end
class Bookmark < ActiveRecord::Base
belongs_to :user
belongs_to :site
end
user.bookmarks.create(:site => Site.find(...) )
The more common pattern is the join model approach for its versatility and better modelling, though habtm
s are still used somewhat. They're just so two-dimensional that you really need to examine what you're doing and make sure there isn't some richer behavior that needs to be modelled as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With