Rails before action check if admin - ruby-on-rails

I installed devise and I've added to the user table a record or column (I'm not sure how to call it) a admin:boolean and by default it's false
In my routes.rb I have created this /admin link
get 'admin' => 'admin#index'
and I'm not sure how to show it only for admin
class AdminController < ApplicationController
before_action: I have no idea what to write here
def index
end
end

Try like this in your controller:
class AdminController < ApplicationController
before_action :is_admin?
def index
end
# it will call before every action on this controller
def is_admin?
# check if user is a admin
# if not admin then redirect to where ever you want
redirect_to root_path unless current_user.admin?
end
end

Related

Devise: restricting page access using user attributes

Relatively new to rails, I've got a simple web app using Devise for user authentication. One attribute is an :admin boolean, set nil for most users, and I will change to true manually in the console for the few users who will need to have administrative access.
My question is: How should I restrict access to a particular page to those who have admin access marked as true?
I've attempted some of that logic in my pages_controller, but it doesn't seem to redirect me as desired (referring to the user_list section):
class PagesController < ApplicationController
before_action :authenticate_user!, :except => [:welcome]
def welcome
#code removed for brevity's sake
end
def dashboard
#ditto
end
def user_list
unless
current_user.admin == true
redirect_to pages_dashboard_path
else
#users = Users.all
end
end
end
Any suggestions on my goal of redirecting or otherwise restricting access to my user_list page would be greatly appreciated.
in your controller you can do something like this
class PagesController < ApplicationController
...
def user_list
if current_user.admin == true
#users = Users.all
else
render :not_an_admin
end
end
end
You can not send them to the same page that they dont have access
You can choose to render a new view
In your user_list method, model name should be singular.
def user_list
unless
current_user.admin == true
redirect_to pages_dashboard_path
else
#users = User.all
end
end

How to inherit from Devise Controllers

I have a user model which uses Devise for authentication and also have an administrator model, which also uses Devise.
I want administrators to be able to edit users profile via administrators/users/{user.id}/edit, however I want this process to be done through Devise Controllers, therefore I tried to inherit from the Users::RegistrationsController as shown below:
class Administrators::UsersController < Users::RegistrationsController
before_action :set_user, only: [:show,:edit,:update,:destroy]
def index
#users=User.all
end
def show
end
def new
super
end
def update
#user.update(user_params)
redirect_to [:administrators,:users]
end
but I get the following error:
Could not find devise mapping for path "/administrators/users". This may happen for two reasons: 1) You forgot to wrap your route inside the scope block. For example: devise_scope :user do get "/some/route" => "some_devise_controller" end 2) You are testing a Devise controller bypassing the router. If so, you can explicitly tell Devise which mapping to use: #request.env["devise.mapping"] = Devise.mappings[:user]
I tried to change the routes but I still get the same error.
Could you please help me?
Inheriting from Devise::RegistrationsController may initially seem like a good idea from a code reuse standpoint but it really not a very good idea.
The intent of the controllers is very different - Devise::RegistrationsController partially deals with an un-authenicated user - and the Devise controllers are scary beasts due to the amount of flexibility built in Devise.
Instead you should just setup a plain old CRUD controller as the task at hand is not very complex compared to clobbering over half of Devise::RegistrationsController.
# config/routes.rb
namespace :administrators do
resources :users
end
# app/controllers/administrators/base_controller.rb
module Administrators
class AuthorizationError < StandardError; end
class BaseController
respond_to :html
before_action :authenticate_user!
# Replace with the lib of your choice such as Pundit or CanCanCan
before_action :authorize_user!
rescue_from AuthorizationError, with: :unauthorized
private
def authorize_user!
raise AuthorizationError and return unless current_user.admin?
end
def unauthorized
redirect_to new_session_path, alert: 'You are not authorized.'
end
end
end
class Administrators::UsersController < Administrators::BaseController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def show
end
def index
#users = User.all
end
def new
#user = User.new
end
def create
#user = User.create(user_params)
respond_with(:administrators, #user)
end
def edit
end
def update
#user.update(user_params)
respond_with(:administrators, #user)
end
def destroy
#user.destroy
respond_with(:administrators, #user)
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Instead you may want to focus on reusing the views through partials for example.
See:
ActionController::Responder
Pundit
CanCanCan

before_action in application controller not been executed first

There is a before_action require_signin in application_controller in Rails 4.2 engine app. The purpose of this require_signin is to check if the user is logged in before any action is executed. Here is require_signin:
def require_signin
if !signed_in?
sign_out
redirect_to URI.escape(SUBURI + main_app.signin_path), :notice => t('Login First!')
end
end
The sign_in? is:
def signed_in?
!current_user.nil?
end
In engine's application_controller, there is:
class ApplicationController < ::ApplicationController
before_action :require_signin
..........
end
Here is an engine resource_allocx's controller namespace:
require_dependency "resource_allocx/application_controller"
module ResourceAllocx
class AllocationsController < ApplicationController
....
end
end
However, in create, a new record is created before the user is kicked out of system asking for login again. Based on the design, if the user is not signed in the require_signin should kick out the user in application_controller and the create should never be executed at all. What have been missed here causing the require_signin executed after create?

Check if user signed in before any action in Rails

I want to execute some function before any controller action to check if the user is signed in. I am using devise so that I can use is_signed_in?, but I have to put if else condition to every method in the controller.
What I want is to have something like this:
#some_controller.rb
before_action :is_signed_in?
def is_signed_in?
if !user_signed_in?
redirect_to new_user_session_path
else
..proceed to the action intended to call
end
end
So I want this method to execute before any action (or some set of actions) and redirect to sign in if false or let that action to be executed if true.
Devise is shipped with some useful built-in helpers.
In your case, one that interested you is authenticate_user!. Take a look at controller filters and helpers in Devise documentation.
You can filter your actions in your controller with this method to ensure only logged-in users can process a given action or all actions in a controller, else if user isn't logged-in then he is redirect to login page.
before_action :authenticate_user!
before_action :authenticate_user!, only: [:show]
You can also create your own helper method.
In your users_controller.rb, create a before_action filter
class UsersController < ApplicationController
before_action :logged_in_user
...
end
and in your session_helper.rb
module SessionHelper
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url
end
end
end
If you want to check whether user is signed for every action in the application, you have to put the filter in the application controller. You can do this for a specific controller also.
You can use the devise method:
class SomeController < ApplicationController
before_action :authenticate_user!
...
end
You can create your own filter also:
class SomeController < ApplicationController
before_action :my_authentication
...
def my_authentication
if user_signed_in?
# do something ...
else
# do something else ...
end
end
end
Are you using devise? You can use existing filter:
class SomeController < ApplicationController
before_filter :authenticate_user!
...
end
if not, create your filter in application controller and add it to your needed controllers:
class SomeController < ApplicationController
before_filter :my_auth_filter
...
end
You can add this method to your ApplicationController
def user_is_logged_in
if !session[:current_user]
redirect_to login_path
end
end
Use it before invoking any actions. Like so,
class AdminsController < ApplicationController
before_action :user_is_logged_in
...
end

undefined local variable or method `authenticate_admin'

I'm trying to view my new action in my blogs controller, but I keep getting the following error message:
NameError in BlogsController#new
undefined local variable or method `authenticate_admin'
In my blogs controller, I want to restrict the new action to admins only (admins and users are two different models). I was able to get this to work in another model. If I'm not mistaken, helpers are open to all classes. I also tried to add the code from my admins helper to the blogs helper, but that didn't work.
Why can't my blogs controller use my authenticate_admin method?
Thanks for lookign :)
Here are relevant files:
blogs_controller.rb
class BlogsController < ApplicationController
before_filter :authenticate_admin, :only => [:new]
def new
#blog = Blog.new
#title = "New Article"
end
end
admins_helper.rb
def authenticate_admin
deny_admin_access unless admin_signed_in?
end
def deny_admin_access
redirect_to admin_login_url, :notice => "Please sign in as admin to access this page."
end
def admin_signed_in?
!current_admin.nil?
end
def current_admin
#current_admin ||= Admin.find(session[:admin_id]) if session[:admin_id]
end
In this case Helpers are accessible in your Views not in Controllers.
Solution is to move your methods from admins_helper.rb to ApplicationController and set them as helper_methods. You will be able to access them in your Controllers and Views.
Example:
class ApplicationController < ActionController::Base
# Helpers
helper_method :authenticate_admin
def authenticate_admin
deny_admin_access unless admin_signed_in?
end
end
Read documentation about helper_method:
http://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html#method-i-helper_method

Resources