Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling different user types in Rails

I'm designing an application that has two [three including administrators] user types: Buyers and Sellers. When a user signs up, it's assumed that they're signing up to simply purchase something [a Buyer account]. However, if they wish to become a Seller, there should be an option for them to post their items for sale, [become a Seller]. This becomes important, as users can switch back and forth between account types.

Of course, a Seller can buy items as well.

The problem

The problem I'm facing is that Sellers have profile pages where buyers can go to view their items for sale, whereas Buyers do not. However, both user types have a My Account page that they can use to update their information.

Possible design choices

Single table inheritence

class User < ActiveRecord::Base
  has_one :profile
end

class Seller < User
  has_many :sale_items
end

class Buyer < User
  # nothing here.. I guess this is the "default" user type
end

I thought about this approach because then I could clearly separate the user types. For example, the show page for each user is clearly separated. However, this could lead to repeated code in each controller, and introduce a problem when switching between user types.


Just use declarative_authorization or CanCan to add functionality to the base user type

class User < ActiveRecord::Base
  has_one :profile
  has_many :sale_items  # only for Sellers
                        # if the user is a seller, allow them to add sale_items
end

I thought of this approach because a Seller is basically a Buyer with additional functionality, such as posting items for sale. This could lead to a lot of view logic, though. For example if @user.role == "seller" render _some_seller_partial. I also don't like the idea of checking for a hard coded string in the view. Well, I guess I could do if @user.seller?

Other design choices?

I'm really interested in hearing how other people would model this application. I've been thinking about this for a couple days now.

like image 605
Feech Avatar asked Oct 17 '11 22:10

Feech


1 Answers

I would use the second option, but with declarative_authorization instead of cancan, and I'd use the role_model Gem to store the role in the user model.

class User < ActiveRecord::Base
  has_one :profile
  has_many :sale_items  # only for Sellers
                        # if the user is a seller, allow them to add sale_items

  #  t.integer :roles_mask , :default => 0    # for role_model
end

declarative_authorization is a bit more powerful than CanCan, and I found it to scale better once a project needs more / more complex roles..

If you store your roles using the role_model Gem, it stores them as a bitmap in the roles_mask attribute. This means that a user can have many roles, e.g. can be a Seller and a Buyer at the same time, and an Admin or Moderator if you like.

See:

http://railscasts.com/episodes/188-declarative-authorization

http://railscasts.com/episodes/189-embedded-association

http://railscasts.com/episodes/192-authorization-with-cancan

http://railscasts.com/episodes/193-tableless-model

And:

http://everydayrails.com/2011/10/06/rails-authorization.html

http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/

like image 195
Tilo Avatar answered Sep 21 '22 16:09

Tilo