Reputation: 6493
I have a Ruby on Rails app with users
, articles
and collaborations
. Here are the relationships:
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
I am successfully able to access both users and articles by going through collaborations so I think everything is set up in my app correctly. Ok on the to question.
I'm using CanCan with an role of :admin
. Basically I only want :admin
to be able to create posts and collaborations and I have that working correctly as well. The question is...how do I write that role into my ability.rb
file such that users who are NOT admin can still collaborate on articles where they are part of a collaboration?"
How should I write that in ability.rb
. It's like I want to say the following: "Users who aren't admins can manage Articles where they are part of a collaboration for that article."
Sorry for being verbose, haven't had my coffee yet :). Here is my 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
Upvotes: 1
Views: 615
Reputation: 1406
Here is a video guide by the author of CanCan that might clearify the correct usage of the gem.
http://railscasts.com/episodes/192-authorization-with-cancan
Dont forget to after setting all the permissions to authorize actions done by the current user in your controller. More documentation on github.
I used CanCan about a year ago and the it was easily set with the command 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
Enjoy the coffee.
Upvotes: 0
Reputation: 1815
Try with the following method.
def initialize(user)
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
end
Upvotes: 0
Reputation: 2469
You can try something like this in your ability.rb file .Just define the role in your users table and use is as enum in your model file like
:role, ["Admin", "Guest", "Other"]
if user.role == "Admin"
if user.role == "admin"
can :manage, :all
else
can :read, Article
end
end
Upvotes: 1
Reputation: 6574
try
can :manage, Article, :collaborations => {:user_id => user.id}
Upvotes: 0
Reputation: 11494
Here's logic in your Ability class that may work for you:
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 allows you to specify the conditions for associations; here, we pass the :user_id
conditions for the :collaborations
association on Article
.
Additional methods added to user:
class User < ActiveRecord::Base
ROLES = [
ADMIN = 'admin'
]
def admin?
role == ADMIN
end
def registered?
persisted?
end
end
To be sure this is working correctly, here's how you might write the tests with RSpec, FactoryGirl and CanCan matchers:
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
Upvotes: 4