CanCan,Rails和Collaboration

bga*_*oci 1 ruby authorization ruby-on-rails cancan

我有一个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
Run Code Online (Sandbox Code Playgroud)

通过协作,我成功地能够访问用户和文章,所以我认为一切都在我的应用程序中正确设置.好的问题.

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

  1. 用户A(谁是管理员)创建文章X.
  2. 用户A使用用户B在Article 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
Run Code Online (Sandbox Code Playgroud)

ros*_*sta 5

这是您的Ability类中可能适合您的逻辑:

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
Run Code Online (Sandbox Code Playgroud)

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

添加到用户的其他方法:

class User < ActiveRecord::Base

  ROLES = [
    ADMIN = 'admin'
  ]

  def admin?
    role == ADMIN
  end

  def registered?
    persisted?
  end

end
Run Code Online (Sandbox Code Playgroud)

为了确保这个工作正常,以下是使用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
Run Code Online (Sandbox Code Playgroud)