CanCan does not allow action but allows html? - ruby-on-rails

For some reason, for a non logged in user, this code displays the html but once delete is clicked CanCan does not allow the action.
<% if can? :destroy, #boat %>
<%= link_to "", boat, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
How do I prevent the HTML from displaying???
def initialize(user)
user ||= User.new
if user.admin? || user.email = 'test#test.io'
can :manage, :all
elsif user.manager?
can :read, Boat
can [:create, :read, :update], User
else
can :read, Boat
can :create, User
end
end

Some how the app was still detecting my email, even while logged out and therefore giving me admin privileges!
Not sure how this is happening...

Related

CanCan: User not being able to view own stuff

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.
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.
<% 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

how to manage CanCan

this is my ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
else
can :read, :all
end
end
end
and index
<% if can? :update, #post %>
<%= link_to t('.edit', :default => t("helpers.links.edit")),
edit_post_path(post), :class => 'btn btn-mini' %>
<% end %>
but I recive error
"NoMethodError in Posts#index undefined method `admin?' for #"
where should I define admin or other roles? And how can i choose admin or anoher role when sign in?
You have to create admin method in User model
def admin?
type == 'Admin'
end
This is in case you have Admin model:
class Admin < User
end

not authorized being shown for admin

I have added a before filter and def check priv to the users controller. It is suppose to be setup so that only admin can view/edit all profiles, and that only the created User can view their own profile. As before anyone could view/edit profiles. I have tried a few methods, none work. When I go to view profile as admin or even regular user I get the "not authorized" message.
Any help would be appreciated.
users_controller:
before_filter :check_privileges, :only => [:edit, :update]
def check_privileges
unless current_user.admin? || current_user.id == params[:id]
flash[:warning] = 'not authorized!'
redirect_to root_path
end
end
index.html:
<%= link_to user.name, user %>
<% if (current_user.admin? || current_user) == #user %>
<%= link_to "Edit #{user} profile", user %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?"} %>
<% end %>
I have a similar method in my app, try something like this:
def check_privileges
return if current_user.admin? # this user is an admin, if is not the case do:
flash[:warning] = 'not authorized!'
redirect_to root_path
end
UPDATE 1
Again, try to change the if condition as the follow
if (condition || condition)
or
if ((condition) || (condition))
The problem is that Ruby parsers stop at the first condition if not explicited declared.
UPDATE 2
I think that there are an error in the parentheses on your index.html.erb, try the following:
<%= link_to user.name, user %>
<% if (current_user.admin? || (current_user == #user)) %>
<%= link_to "Edit #{user} profile", user %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?"} %>
<% end %>
Food for thought maybe you could do something like this:
def correct_user
#user = User.find(params[:id])
if current_user.role? :administrator
#Allow admin to access everyone account
else
access_denied unless current_user?(#user)
end
end
Then inside your view your view do the if statement. Or alternatively my best suggestion is to go with something like CanCan. Something like this will allow you to set up role authentication really easily. If you have a look at it you can set a certain amount of rule in your ability.rb which you can then enforce on the view.
If you WERE to go with the method of CanCan you could do something like this in your ability.rb
def initialize(user)
user ||= User.new # guest user
# raise user.role?(:administrator).inspect
if user.role? :administrator
can :manage, :all
can :manage, User
elsif user.role? :employee
can :read, :all
end
The above is an example.... So that in your views you can enforce this type of rule by doing something like
<%= link_to user.name, user %>
<% if can? :manage, #user %>
<%= link_to "Edit #{user} profile", user %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?"} %>
<% end %>
Something like this should work. Your options are there hope this helps :)

Issues with Cancan and rails_admin with devise

So I have setup rails_admin with devise and cancan, I have it so that only admins can access the /admin pages.
But when trying to only show certain code to admins using <% if user_admin? %> I get undefined methoduser_admin?' for`
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
can :access, :rails_admin #grant access to rails_admin
can :dashboard #gives access to the dashboard
else
can :read, :all
end
end
end
_header.html.erb
<% if user_admin? %>
<li><%= link_to 'Settings', edit_user_registration_path %></li>
<li><%= link_to 'Logout', destroy_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to "Create Account", new_user_registration_path %></li>
<li><%= link_to "Login", new_user_session_path %></li>
<% end %>
I needed to set the abilities up in the ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
can :access, :rails_admin #grant access to rails_admin
can :dashboard #gives access to the dashboard
else
can :read, :all
end
end
end
Then was able to just call
<% if can? :access, :rails_admin %>
<li><%= link_to 'Admin', rails_admin_path %></li>
<% end %>
I can now do if can? on anything I want to authorize.

CanCan authorization issue

I am using cancan for my app
my ability.rb class is
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :admin
can :manage, :all
elsif user.role? :operations
can :manage, :all
elsif user.role? :customer_support
can :read, :all
else
user.role? :marketing
can :read, :all
end
end
end
and i add method in user.rb
def role?(role)
self.roles.include? role.to_s
end
I also add
load_and_authorize_resource in my controller say products_controller which can authorise user and allow him to do certain action in this controller,
but my problem is when user gets logged in with admin as role he can't be able to add new product, it gives access denied error of cancan.
my view is
<% if can? :create, Product %>
<td class="action"><%= link_to 'Show', product %></td>
<td class="action"><%= link_to 'Edit', edit_product_path( product) %></td>
<td class="action"><%= link_to 'Destroy', product, :confirm => 'Are you sure?', :method => :delete %></td>
<% end %>
it also not showing this link to admin as there are all access to admin but still he can't access this action?
what else am I missing?
plz help?
Have you followed instructions in the cancan wiki? https://github.com/ryanb/cancan/wiki/Role-Based-Authorization.
Cancan default strategy for storing roles for each user is using a bitmask, but the wiki mentions about a different solution here: https://github.com/ryanb/cancan/wiki/Separate-Role-Model.

Resources