views:

56

answers:

3

I want to make a simple login, logout, also, different user have different user role. The Restful authentication seems works great, and the cancan is also very sweet for controlling user ability. But the question is how can I let these two works together. I watched the railcast, I was whether how to detect the user ability? Do I need to add a "ability" column in the user table?? Thank u.

http://railscasts.com/episodes/67-restful-authentication

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

+1  A: 

Look at the CanCan GitHub page: http://github.com/ryanb/cancan

Based on looking at both that and the RailsCast, I notice two things:

  1. You define Ability as a separate model. There doesn't appear to be any necessary database columns.
  2. There is no way you are forced to do roles, you are free to do this however you will.

With restful_authentication, just do the normal thing with your User model.

The most natural way to add CanCan would be to add an extra column to your User model called role or ability or something, then define methods as you see fit. Personally I'd probably do some kind of number system stored in the database, such as "0" for admin, "1" for high-level user, "2" for low-level user, etc.

Here's a few possibilities:

# Returns true if User is an admin
def admin?
  self.role == 0
end

And:

# Returns true if User is admin and role?(:admin) is called, etc.
def role?(to_match)
  {
    0 => :admin,
    1 => :super_user,
    2 => :user,
    3 => :commenter,
  }[self.role] == to_match
end

Then in your Ability initialize method, you can use some kind of conditionals to set abilities, such as these snippets from the Railscast/readme:

if user.role? :admin
  can :manage, :all
elsif user.role? :super_user
  ...
end

Or:

if user.admin?
  can :manage, :all
else
  ...
end
Karl
So, the user is calling the role column, just for get back the security number only, right?
Tattat
The role column is just to return different numbers representing different types of users, so you know what abilities to give them.
Karl
A: 

I wrote a simple solution that works with CanCan too, just add a role_id:integer column to the User model:

# puts this in /lib/
module RolePlay
  module PluginMethods
    def has_roleplay(roles = {})
      @@roles = roles
      @@roles_ids = roles.invert

      def roles
        @@roles
      end

      def find_by_role(role_name, *args)
        find(:all, :conditions => { :role_id => @@roles[role_name]}, *args)
      end

      define_method 'role?' do |r|
        r == @@roles_ids[role_id]
      end

      define_method :role do
        @@roles_ids[role_id]
      end
    end
  end
end

then include this line in config/initializers/roleplay.rb

ActiveRecord::Base.extend RolePlay::PluginMethods

finally use it in your User model:

class User < ActiveRecord::Base
  # ...
  has_roleplay(:admin => 0, :teacher => 1, :student => 2)
  # ...
end

now your model will have 2 new methods:

@user.role?(:admin) # true if user has admin role
@user.role # returns role name for the user
apeacox
A: 

Here is a complete walk through to using Devise for auth and CanCan for roles: http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/

Contact me if you need more instruction.

Tony