我目前一直在研究如何根据我们想要的每个条件来分离 CanCan 的角色。 在我们的应用程序中,有很多类别(例如数学、英语、历史等),每个类别中都有很多类(class)。
每个用户可以在每个类别中扮演许多不同的角色。例如,约翰可以是数学的“读者”,这意味着他可以阅读所有数学类(class)。约翰也可以是英语的“作家”,这意味着他可以阅读所有英语类(class),在类别英语中创建类(class),并仅编辑/删除他创建的英语类(class)。
如果这些是 John 仅有的角色,他将无法在导航栏中看到类别历史记录,并且将被拒绝访问历史记录中的类(class)。
这些是关系的建立方式:
class User < ActiveRecord::Base
has_many :roles
def has_role?(role_sym)
roles.any? { |r| r.level.underscore.to_sym == role_sym }
end
end
class Category < ActiveRecord::Base
has_many :roles
has_many :courses
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :category
attr_accessible :level, :category_id, :user_id
end
在 model/ability.rb 中我们有
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in) #guest
if user.has_role? :reader
reader(user)
end
if user.has_role? :writer
writer(user)
end
end
#BE ABLE TO SEE COURSES AND CATS FOR PERMITTED CATS.
def reader(user)
can :read, Category, :roles => { :user_id => user.id, :level => "reader" }
## how would we be able to limit reading of courses that are within permitted categories? something like category.courses ~~
end
def writer(user)
reader(user) #inheriting from reader? this doesnt work because level is hardcoded into reader
can :read, Category, :roles => { :user_id => user.id, :level => "writer"}
# 1.you can read all courses in category that you are given permission to
# 2.you can write courses in permitted category
# 3.you can edit, delete courses that only youve created within permitted category
end
end
问题:
我们如何正确区分“读者”和“作者”的角色?我们如何访问我们有权访问的类别中的类(class)?
在 ability.rb 中定义了 reader 和 writer 方法后,我们如何在 View 页面中使用它们?看起来当前文档使用类似 "<% if can? :read, @category %> "但这并没有使用我们分离和定义的方法。
附注我们将有 7 个不同的角色:访客、读者、作者、编辑、经理、管理员和 app_admin(我们的开发人员)
我已经尝试解决这个问题 3 天了 - 请理解我仍然是一个初学者!提前致谢
最佳答案
我今天遇到了同样的需求,并在 CanCan Wiki 上找到了一种方法来做到这一点.
简单地遵循这些简单的步骤:
1) 使用您的角色名称在 User 类下创建一个常量:
class User < ActiveRecord::Base
ROLES = %w[admin moderator author banned]
end
2a) 如果您使用的是 ActiveRecord,则创建并运行迁移:
rails generate migration add_roles_mask_to_users roles_mask:integer
rake db:migrate
2b) 如果您使用的是 Mongoid,请在用户模型中添加这些字段:
field :roles_mask, type: Integer
3) 接下来您需要将以下代码添加到用户模型中:
# in models/user.rb
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
end
def roles
ROLES.reject do |r|
((roles_mask.to_i || 0) & 2**ROLES.index(r)).zero?
end
end
4) 如果您使用的设计没有强参数,请不要忘记将 attr_accessible :roles 添加到您的用户模型中。如果您使用带有 strong_parameters 的设计,无论是作为 Rails 3 应用程序中的 gem,还是作为 Rails 4 中的内置工具,请不要忘记将角色添加到 Controller 中的允许列表中:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :password, :password_confirmation, roles: [])}
end
end
5) 添加以下代码以在 View 中生成用于设置这些角色的复选框:
<% for role in User::ROLES %>
<%= check_box_tag "user[roles][#{role}]", role, @user.roles.include?(role), {:name => "user[roles][]"}%>
<%= label_tag "user_roles_#{role}", role.humanize %><br />
<% end %>
<%= hidden_field_tag "user[roles][]", "" %>
6) 最后,您可以在 Ability 类中添加一种方便的方法来检查用户的角色:
# in models/user.rb
def is?(role)
roles.include?(role.to_s)
end
# in models/ability.rb
can :manage, :all if user.is? :admin
就是这样。
希望对您有所帮助。
关于ruby-on-rails - rails : Using CanCan to define multiple roles depending on instances of single Model?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18482747/