CanCan: User not being able to view own stuff

119 views Asked by At

I made a simple role based auth with Sorcery and Cancan, which database holds a column named ROLE that when registering a user can be admin or normal,

Relato is a scaffold where you can create "Reports" i wanted to normal user can only see those created by himself and do other stuff(update,destroy) as well.

my ability.rb

def initialize(user)

 if user.role == 'admin'
  can :manage, :all
 elsif user.role == 'normal'
   can :create, Relato
   can :manage, Relato, :user_id => user.id
   can [:read, :update, :destroy], User, :id => user.id

 end

no need for control protection

in my view index.html.erb where it lists all "reports" i put

<% if can? :index, Relato %> 
<tbody>
<% @relatos.each do |relato| %>
  <tr class="alt">
    <td><%= relato.cliente.name %></td>  
     <td><%= relato.projeto.name %></td>  
      <td><%= relato.local_id %></td>  
      <td><%= relato.task_id %></td>  
      <td><%= relato.time %></td>  
     <td><%= relato.comment %></td>  
    <td><%= relato.isdoe %></td>  
       <td><%= link_to 'Editar', edit_relato_path(relato) %></td>  
      <td><%= link_to 'Deletar', relato, method: :delete, data: { confirm: 'Are you sure?' } %>
    </tr>
   <% end %>
<% end %>

But it doesn't work, the user can't see his reports, using admin account everything is fine.

2

There are 2 answers

4
max On
<% if can? :read, Relato %> 

Not @Relatio.

Also you might want to consider using cascading abilities. Simply put an admin gets all the abilities of a normal user. Plus he gets some special admin abilities. To show why this is a good idea imagine if realize that you also need a editor role:

def initialize(user)
  if user.role == 'admin'
    can :manage, :all
  elsif user.role == 'normal'
    can :create, Relato
    can :manage, Relato, :user_id => user.id
    can [:show, :update, :destroy], User, :id => user.id
  elsif user.role == 'editor'
    can :manage, Relato 
    can [:show, :update, :destroy], User, :id => user.id
  end
end

Thats alot of duplication. Instead:

def initialize(user)

  # Anybody can change their profile
  can [:show, :update, :destroy], User, :id => user.id

  # Anybody can edit Relatos they own.
  can :manage, Relato, :user_id => user.id

  if user.role == 'admin'
    can :manage, :all
  end

  if user.role == 'editor'
    can :manage, Relato
  end
end
8
RPinel On

Since you have a collection of @relatos, you should not rely on a instance of Relato to check the ability.

Consider using something like can?(:index, Relato). Notice that I'm using the class.

Now you can setup the ability, but since the class is being used, you cannot check check attributes like user_id.

Since you have can :manage, :all for admin, they should be able to read the @relatos.

Let me know if you were trying to achive something else.