So I have a Post
model. My posts
can be either published or unpublished. I am using Rolify, CanCanCan and Devise.
What I want to happen is my :admin
users, should be able to view the Post#Show
action of all Posts, but my :member
or guest
users (i.e. non-logged in) should only ever be able to see Post.published
posts.
My ability.rb
looks like this:
if user.has_role? :admin
can :manage, :all
#Member
elsif user.has_role? :member
can :read, :all
can :create, Post
can :status, Post
can :update, Post do |post|
post.try(:user) == user
end
#Guest
else
can :read, :all
can :create, Post
can :status, Post
end
I tried doing this, for both :member
and Guest
, but it gave me an endless redirect loop on my Post#Index
page - which is my root_path
:
can :read, Post.published
Where Post.published
returns an array of all the posts with publication_status = "published"
.
This is how I declared that on my Post.rb
:
enum publication_status: [ :unpublished, :published ]
How do I achieve this?
I figured this out.
In my Post#Show
, I simply did this:
def show
if current_user and current_user.has_role? :admin or :editor
@post = Post.find(params[:id])
else
@post = Post.published.find(params[:id])
end
end
That works like a charm.
If someone has a more elegant way, say inside the ability.rb
I would love to know.
I tried many permutations using blocks and all this jazz in the ability.rb
but nothing worked.
I also had to remove the default added set_post
method in my controller, because cancancan
already loads_and_authorize
the resource.