简体   繁体   中英

Correct implementation of many-to-many in Ruby on Rails?

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.

Railscasts is the most reliable source of wisdom :) Rayan Bates teach a true "rails way" to solve problems in ruby on rails applications. You should definitely do it this way.

But if you want to learn more about associations then please follow this link http://guides.rubyonrails.org/association_basics.html

Happy coding!

As others have mentioned, Rails makes this all pretty easy using either has_and_belongs_to_many or has_many though .

I wouldn't say that one is "more right" than the other, it just depends on what you need to do, specifically around how you need to manipulate the joined models. Deciding between them is discussed here .

(All those references are from the association doc already provided.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM