8
votes

I've started a Rails application with Devise and CanCan. I have users which has a one-to-many relationship to articles. I'm new to CanCan, here's what I'm planning to do:

Admin

  • can do any action on articles

Logged in user

  • can read and create articles
  • can edit and destroy his own articles

Guest user

  • can read articles

But I'm having trouble understanding the syntax of CanCan. I understand it would be something like this.

def initialize(user)
  user ||= User.new
  if user.admin?
    can :manage, Article
  else
    can :read, Article
  end
end

But this is just for the admin and guest user, I'm not sure how to differentiate a guest user from a logged in user because it creates a new User object when user is empty. I've seen that the code should be something like this can [:edit, :destroy], Article, :user_id => user.id, but I'm not sure how this would fit in the initialize method.

And one last question, if I only define a can :read, Article on guests, would it block the other actions such as create and update, like white listing the read action?

Any help would be appreciated. Thanks a lot!

2

2 Answers

22
votes

Here's what I did:

In ability.rb

def initialize(user)
  if user.nil?
    can :read, Article
  elsif user.admin?
    can :manage, Article
  else
    can [:read, :create], Article
    can [:update, :destroy], Article, :user_id => user.id
  end
end

And for displaying the links, I've used this:

- if can? :read, Article
  = link_to 'Show', article
- if can? :create, Article
  = link_to 'New Article', new_article_path
- if can? :update, article
  = link_to 'Edit', edit_article_path(article)
- if can? :destroy, article
  = link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' }

And it seems to be working now, not sure if that's the best way though.

8
votes

You can pass hash of conditions:

can :manage, Article, :user_id => user.id

Look at https://github.com/ryanb/cancan/wiki/defining-abilities for details.