1

我有一个 Ruby on Rails 应用程序,其中包含users,articlescollaborations. 以下是关系:

User has_many :articles
User has_many :collaborations

Article belongs_to :users
Article has_many :collaborations

# Collaboration has collaboration.id collaboration.user_id and collaboration.article_id.
Collaboration belongs_to :users
Collaboration belongs_to :articles

通过协作,我成功地访问了用户和文章,因此我认为我的应用程序中的所有内容都已正确设置。好的,关于问题。

我正在使用CanCan的角色:admin。基本上我只希望:admin能够创建帖子和协作,并且我也可以正常工作。问题是......我如何将该角色写入我的ability.rb文件,以便非管理员用户仍然可以在他们参与协作的文章上进行协作?”

  1. 用户 A(管理员)创建文章 X
  2. 用户 A 与用户 B 在文章 X 上创建协作
  3. 用户 B 登录但只能编辑和更新文章 X

我应该怎么写ability.rb。就像我想说以下内容一样:“不是管理员的用户可以在他们参与该文章的协作时管理文章。”

对不起,我还没有喝咖啡:)。这是我的ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user
    if user.role == "admin"
      can :manage, :all
    else
      can :read, Article
      # this is where I want to say: can :manage if part of collaboration for article 
    end
  end
end
4

5 回答 5

5

以下是您的能力类中可能对您有用的逻辑:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user
    case
    when user.admin?
      can :manage, :all
    when user.registered?
      can :read, Article
      can :manage, Article, :collaborations => { :user_id => user.id }
    else # user.guest?
      can :read, Article
    end
  end
end

CanCan 允许您指定关联的条件;在这里,我们在 上传递关联的:user_id条件。:collaborationsArticle

添加到用户的其他方法:

class User < ActiveRecord::Base

  ROLES = [
    ADMIN = 'admin'
  ]

  def admin?
    role == ADMIN
  end

  def registered?
    persisted?
  end

end

为确保它正常工作,以下是使用 RSpec、FactoryGirl 和 CanCan 匹配器编写测试的方法:

require 'spec_helper'
require "cancan/matchers"

describe Ability do
  subject { Ability.new(user) }

  context "admin" do
    let(:user) { create(:admin) }

    it { should be_able_to(:manage, :all) }
  end

  context "user" do
    let(:user) { create(:user) }

    it { should be_able_to(:read, Article) }

    it "cannot manage articles without collaborations" do
      article = create(:article)
      should_not be_able_to(:manage, article)
    end

    it "cannot manage articles only others collaborated on" do
      article = create(:article)
      article.collaborations.create { |c| c.user = create(:user) }
      should_not be_able_to(:manage, article)
    end

    it "can manage article with collobaration" do
      article = create(:article)
      article.collaborations.create { |c| c.user = user }
      should be_able_to(:manage, article)
    end
  end

  context "guest" do
    let(:user) { User.new }

    it { should be_able_to(:read, Article) }
    it { should_not be_able_to(:manage, Article) }
  end
end
于 2012-10-07T23:45:45.780 回答
1

您可以在您的能力.rb 文件中尝试这样的事情。只需在您的用户表中定义角色并在您的模型文件中使用 is 作为枚举

:角色,[“管理员”,“访客”,“其他”]

if user.role == "Admin"
      if user.role == "admin"
            can :manage, :all
      else
           can :read, Article
      end
end
于 2012-10-08T13:08:38.873 回答
0

尝试

can :manage, Article, :collaborations => {:user_id => user.id}
于 2012-10-05T13:41:17.357 回答
0

试试下面的方法。

定义初始化(用户)

user ||= User.new
if user.admin?
    can :manage :all
elsif user.registered?
    can :manage, Article, :collaborations=>{:user_id=>user.id}
    can :read,  Article
else
    can :read,  Article
end

结尾

于 2012-10-10T07:32:25.653 回答
0

这是 CanCan 的作者提供的视频指南,可能会阐明 gem 的正确用法。

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

不要忘记在设置所有权限以授权当前用户在控制器中执行的操作之后。更多文档在github 上

大约一年前我使用了 CanCan,它很容易用命令设置load_and_authorize_resource

Class ArticlesController > ApplicationController
  load_and_authorize_resource #authorize all actions based on ability.rb

  def index
    ## manual authorization ##
    @articles = Article.all
    authorize! :read, @articles #Manually authorize this action. You dont need this if you put load_and_authorize_resource on top. 
    ## end manual authorization ##
  end

  def show 
    #@article = Article.find(params[:id]) #already loaded and authorized through load_and_authorize_resource
  end

end

享受咖啡。

于 2012-10-10T13:51:22.580 回答