hellomello
hellomello

Reputation: 8597

handling user sign up roles with RoR?

I was wondering what would be the most logical way of handling which type of user a user would sign up?

When a user registered their say:

name, email, password

They get redirected to another page asking which role they're interested in signing up:

business or resident

Should I just assign a new column in users table in their database? string :role? Or should I create a new table? And what gem would work best for handling something like this? Eventually I would want to output different view layouts depending on user's role

Thanks

Upvotes: 1

Views: 214

Answers (2)

Deej
Deej

Reputation: 5352

As I stated the best gem for something like this would be CanCan because it allows you to alter your roles to how you want. With the ability to filter out particular actions for different roles. To go about this I suggest to do the following:

1. Adding Roles

rails g scaffold Role name:string 

2. HABTM relationship between roles and users

rails generate migration UsersHaveAndBelongsToManyRoles

class UsersHaveAndBelongsToManyRoles < ActiveRecord::Migration
  def self.up
    create_table :roles_users, :id => false do |t|
      t.references :role, :user
    end
  end

  def self.down
    drop_table :roles_users
  end
end

3.Modify the Role model, so it looks like the following

class Role < ActiveRecord::Base
  has_and_belongs_to_many :users
end

4. Altering User model

Add :role_ids to attr_accessible so that you can then add the following method to identify the role of a particular user.

 class User < ActiveRecord::Base
  has_and_belongs_to_many :roles

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :username, :password, :password_confirmation, 
  :remember_me, :role_ids

  def role?(role)
    !!self.roles.find_by_name(role.to_s.camelize)
  end
end

5. Seeding roles

%w(Business Administrator Resident).each { |role| Role.create!(:name => role) }

The above is a literal array of the roles

So you could do something like this as an example:

b = User.create!(:email => "[email protected]",
                 :password => "pass",
                 :password_confirmation => "pass",
)
b.roles << Role.first
b.save

6. Registration form

Your registration form may look like the following this is an example:

<%= form_for(@user) do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %>
           prohibited this user from being saved:</h2>

      <ul>
        <% @user.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= f.label :email %><br />
    <%= f.text_field :email %>
  </div>
  <% if @current_method == "new" %>
    <div class="field">
      <%= f.label :password %><br />
      <%= f.password_field :password %>
    </div>
    <div class="field">
      <%= f.label :password_confirmation %><br />
      <%= f.password_field :password_confirmation %>
    </div>
  <% end %>
  <% for role in Role.find(:all) %>
    <div>
      <%= check_box_tag "user[role_ids][]", 
           role.id, @user.roles.include?(role) %>
      <%= role.name %>
    </div>
  <% end %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

The above form will allow the user to select their role.

6. Migrate your database rake db:migrate

7. Defining permissions using CanCan

Generate the ability class using - rails g cancan:ability

Ability.rb

class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= User.new # guest user

    if user.role? :administrator

      can :manage, :all
      can :manage, User

    elsif user.role? :business
      can [:create, :new], Business
      can [:show, :update], User, :id => user.id 

    else user.role? :resident 
     can [:show, :update], User, :id => user.id

    end
  end
end

As you stated you want to show different parts of a page to different users. So you may have on a particular view the following if-else

Example View

  <% if current_user.role? business %> 

     #Show stuff visible to business user

   <% else current_user.role? resident %> 

      #Show stuff visible to resident user

 <% end %> 

Hopefully this gives some clarity on what you want to do

Filter example:

 def admin_business_user
    redirect_to dashboard_path, :notice => 
    'You must be an admin to do that!' 
          unless current_user.role? :administrator || :business 
  end

Upvotes: 4

JimmyT
JimmyT

Reputation: 73

If you are only going to have 2 roles then it is probably easiest to add a column to your users model.

rails generate migration add_business_to_users business:boolean

Then in the migration add a default to this column like

class AddBusinessToUsers < ActiveRecord::Migration
  def change
    add_column :users, :business, :boolean, default: false
  end
end

Once you have migrated this to your database you have everything you need for 2 roles. For example you can always use

user.business? #This will be true for a user that is a business and false for resident

What you are effectively assuming is that every user that is not a business is a resident.

If you are going to have more roles then it makes sense to have a separate roles model or use a gem like cancan.

Upvotes: 1

Related Questions