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.
Related
I'm managing user and admin roles with cancan. I want the user to have access to certain views ("Cursos", "Credenciales", ) but cancan does not allow it. How can I give them access? So, what is happening is that it tries to access the route but goes back to the root as I specified it to do it in the application controller. (Of course it is supposed to access to the controller through that route.) Thanks for your help!!
index.html.erb
<% if current_user %>
<% if can? :new, #user %>
<% if can? :new, #empleado %>
<li><%= link_to "Lista de Empleados", empleados_path %></li>
<li> <%= link_to "Agregar Empleado", new_empleado_path %></li>
<% end %>
<% end %>
<li><%= link_to "Cursos", cursovence_path %></li>
<li><%= link_to "Credenciales", credencialvence_path %></li>
<% end %>
ability.rb
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.admin?
can :manage, :all
else
can :read, :all
can :display, :all
end
end
routes.rb
devise_for :users
root 'empleados#index'
resources :empleados
resources :users
post '/empleados/:id' => 'empleados#display'
get '/cursovence' => 'empleados#indexCursoVence'
get '/credencialvence' => 'empleados#indexCredencialVence'
get '/proxvacas' => 'empleados#indexProxVacas'
empleados_controller.rb
class EmpleadosController < ApplicationController
before_action :authenticate_user!
# load_and_authorize_resource - It did not work with this validation
load_resource #So, I changed it for only this one
def index
....
end
def new
....
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
rescue_from CanCan::AccessDenied do |exception|
flash[:error] = "Access denied."
redirect_to root_url
end
end
In cancan you can assign abilities based on symbols not classes (in case you don't have models to base your abilities on) https://github.com/ryanb/cancan/wiki/Non-RESTful-Controllers
So in your view check for can? :index, :cursos and can? :index, :credenciales given that you added can :read, :all in your ability
<% if can? :index, :cursos %>
<li><%= link_to "Cursos", cursovence_path %></li>
<% end %>
<% if can? :index, :credenciales %>
<li><%= link_to "Credenciales", credencialvence_path %></li>
<% end %>
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...
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
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 :)
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.