其他答案表明有幾種方法可以解決這個問題。首先,確保您瞭解身份驗證(創建用戶並登錄)和基於角色授權(根據用戶角色控制對Web應用程序不同部分的訪問)之間的區別。您可以自己實現身份驗證,但大多數Rails開發人員使用Devise gem,因爲它的功能強大,功能全面且經過良好測試。儘管開發人員經常使用CanCanCan或Pundit寶石作爲複雜應用程序,但可以通過對用戶模型的簡單添加來實現授權。
對於您描述的用例,我建議在用戶模型中實施基本的基於角色的授權形式。首先,您必須使用Devise創建用戶模型。
Rails 4.1中引入的Active Record,Enum的新功能是實現基於角色的授權的最簡單方法。
創建遷移:
$ rails generate migration AddRoleToUsers role:integer
遷移將是這樣的:
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :integer
end
end
代碼添加到您的用戶模型來實現的枚舉:
class User < ActiveRecord::Base
enum role: [:student, :parent, :teacher, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :student
end
end
你定義角色名稱,如有必要,可以根據需要更改名稱(與每個用戶存儲在一起的整數值)繩索保持不變)。 Active Record將限制屬性的賦值給一個預定義的值的集合,所以你不必添加任何代碼來將角色的名字限制在一個已定義的集合中。最重要的是,枚舉帶有一套便利方法,可以讓您直接查詢角色而無需額外的代碼。對於上面顯示的枚舉屬性,可以使用以下方法:
User.roles # => {"student"=>0, "parent"=>1, "teacher"=>2, "admin"=>1} # list all roles
user.student! # make a student user
user.student? # => true # query if the user is a student
user.role # => "student" # find out the user’s role
@users = User.student # obtain an array of all users who are students
user.role = 'foo' # ArgumentError: 'foo' is not a valid, we can’t set invalid roles
可以使用條件語句中的控制單元,
class UsersController < ApplicationController
def index
unless current_user.admin?
redirect_to :back, :alert => "Access denied."
end
@users = User.all
end
end
或者在視圖中使用它:
<% if current_user.parent? %>
<li><%= link_to 'Grade Reports', some_path %></li>
<% end %>
一般情況下,如果訪問控制將大量代碼添加到控制器中,則建議您使用CanCanCan或Pundit,因爲您可以將複雜的授權邏輯移動到中心從控制器(「瘦身控制器」)分離的位置。但是,如果您的需求如您所描述的那樣簡單,那麼控制器中基於角色的授權是最佳選擇。
我寫了一本Rails Pundit教程,該教程比較了兩種方法,並提供了有關基於角色的簡單授權以及使用Pundit進行基於角色的授權的更多詳細信息。
'type'屬性是爲單表繼承保留的,在這種情況下可能適用,但至少應指定此答案意味着STI,學生和教師模型應從用戶繼承。 –
感謝您的評論@ CV-Gate。我修改了我的答案。這裏我沒有使用STI。 – lsaffie