Search code examples
ruby-on-railscancancan

Using CanCanCan - I am clearly doing something obviously wrong


Good evening,

CanCanCan is great; however, I think I am missing something incredibly obvious, as my Model logic is pretty straight forward.

  • A signed-in user who produced the thing should be able to Read, Update & Delete
  • If a signed-in user not the thing author should be able to Read & Comment on the thing.
  • Someone not signed in should be able to read and/or search.

Steps 1 and 3 work. However, step 2 is not working - if another user is signed-in, tries to look at a thing; they see "CanCan::AccessDenied" unless it is their thing.

Ability.rb

    if user.present?
      can :manage, List, user_id: user.id 
    else
      can [:read, :search], List 
    end

Is user.present? linked/locked to current_user in the above snippet? I've tried omitting .present? However, that still renders CanCan::AccessDenied.

Upon this unexpected error, I thought something like the below would work, alas not.

    if user.present? 
      can :manage, List, user_id: user.id 
    elsif @list.find(params[:id]).user != user
      can [:read], List
    else
      can [:read, :search], List 
    end

For posterity please find my solution building on top of what Roman Alekseiev provided.

application controller

class ApplicationController < ActionController::Base
    load_and_authorize_resource :parent
    load_and_authorize_resource :child, through: :parent

ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= ::User.new

    if user.new_record?
      can [:read, :search], Parent
      can [:read], Child
    else
      can [:read, :search], ::Parent
      can [:read, :create, :delete], Child
      can :manage, Parent, user_id: user.id
    end
end

How to use the ability in a view, for example show.

<% if can? :create, @parent => Child %>
present the child markup/content
<% end %>

More Reading via the official documentation


Solution

  • From my point of view:

      def initialize(user)
        user ||= ::User.new
    
        if user.new_record?
          can [:read, :search] ::List
        else
          can [:read, :comment], ::List
          can :manage, ::List, user_id: user.id
        end
    

    Tried with this article, source