ruby-on-rails – Rails:使用CanCan根据单个模型的实例定义多个角色?

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – Rails:使用CanCan根据单个模型的实例定义多个角色?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_301_0@
我目前仍然坚持如何根据我们想要的每个条件来分离CanCan的角色.
在我们的应用程序中,有许多类别(如数学,英语,历史等),每个类别都有很多课程.

每个用户可以在每个类别上拥有许多不同的角色.例如,John可以成为数学的“读者”,这意味着他可以阅读所有数学课程.约翰也可以成为英语的“作家”,这意味着他可以阅读所有英语课程,在英语类别中创建课程,只编辑/删除他在英语中创建的课程.

如果这些是约翰所拥有的唯一角色,他将无法在导航栏中看到类别历史记录,并且将无法访问历史记录中的课程.

这些是建立关系的方式:

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,: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

问题:

>我们如何以正确的方式分离“读者”和“作家”的角色?我们如何访问我们可以访问的类别中的课程?
>在ability.rb中定义reader和writer方法之后,我们如何在视图页面中使用它们?看起来当前的文档使用类似“<%if can 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,请在User模型上添加这些字段:

field :roles_mask,type: Integer

3)接下来,您需要将以下代码添加到User模型:

# 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中内置的,都不要忘记将角色添加到控制器中的允许列表中:

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)在视图中添加以下代码生成用于设置这些角色的复选框:

<% 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相关文章