Rails has many and belongs to

2019-09-08 19:47发布

问题:

I am building a daily deal app to better learn Ruby on Rails.

On M. Hartly tutorial, I understood the concept of models and their relationship (a microposts belongs_to a user, and a user has_many microposts).

However I am not sure how to put that into practice on my daily deal project.

I decided to have a Model for users with two type of users with different rights:

  • admin_user who can create/update/edit/delete the deals

  • standard_user who can see the deals and if they find one interesting participate in a deal

Both users go into the users database

I also decided to have a model for deals and go in the Deals database So have I understood well:

  • a admin_user has_many deals

  • deals belongs to a admin_user

  • standard_user has many deals (indeed he can participate in many deals)

  • and deals do NOT belong to standard_user so I can’t say anything here.

Have I understood things right? It is possible to define according to the type of right of a user different relationship to a model object(in this case: deals)

PS: I think I’ll separate users with cancan gem to give them different rights

回答1:

The biggest issue with what you're describing is that a standard_user has_many :deals, but deals don't belong to a standard_user; they probably are in use by many standard users at the same time. That means that a deal can't belong_to a standard_user, because you can't have a standard_user_id column in your Deals table (since you'd need arbitrarily many columns to deal with the arbitrarily many users who might participate).

In order to have a many-to-many relationship like this, you need a link table. Here's one way to achieve this in Rails:

class DealParticipation < ActiveRecord:Base
  #This means the deal_participations table has a standard_user_id key
  belongs_to :standard_user
  #This means the deal_participations table has a deal_id key
  belongs_to :deal

  #... more logic goes here ...
end

Now your standard user looks like:

class StandardUser < ActiveRecord::Base
  has_many :deal_participations
  has_many :deals, :through => :deal_participations
  # ... more logic goes here ...
end

And your deal class looks like:

class Deal < ActiveRecord::Base
  has_many :deal_participations
  has_many :standard_users, :through => :deal_participations
  belongs_to :admin_user
  #... more logic goes here ...
end

You'll then need three tables: one for deals, one for deal_participations, and one for standard_users (plus the stuff for admin users).

Depending on your needs, you may also want to try using single-table inheritance (STI) to make Users and Admin Users derive from a common base class. You can read more about STI here.

I hope that helps! Enjoy getting started with Rails!



回答2:

Assuming that each deal is associated with a single admin_user, then I think you're first three bullets are correct. With respect to your fourth bullet, however, you could use has_many :through or has_and_belongs_to_many to model the relationship between standard_user and deal as discussed in this Rails guide. In the latter case, standard_user's has_many relationship to deal would change to has_and_belongs_to_many.

As for using User subclasses to define relationships, yes, you can do this, but see http://guides.rubyonrails.org/association_basics.html for a general discussion of this approach.

Pete