before_action in application controller not been executed first - ruby-on-rails

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?

Related

Keep users from accessing pages in Rails app if they're not logged in

I'm fairly new to Rails and am building a webapp to learn. I currently have the webapp working to accept new users and log them in. However, I want to block access to pages other than the login page when users aren't logged in. I've searched for hours and nothing I have found has worked. I don't want to use to Devise. Here is my code:
Application controller:
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
before_action :logged_in_user
end
Session Helper:
module SessionsHelper
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
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 'name of login page'
end
end
end
Currently, the page just reloads over and over (because the user isn't logged in) and the page times out. What am I doing wrong?
when you use before_action in the ApplicationController the specified action will run before any action in all controller that inherits ApplicationController unless you skip it by skip_before_action.
In your case you need either to apply before_action in ApplicationController and use skip_before_action before login action in for example in the SessionsController or you can only use before_action in all other controllers instead of ApplicationController to specify when you need them to run.
class SessionsController
skip_before_action :logged_in_user, only: :login
def login
end
end
Also remember to handle when a user is already logged in and he tries
to visit the login page.

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

Rails before action check if admin

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

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

A controller before_filter has no effect

In Rails 4, I use before_action :require_login for my UserController. This is supposed to redirect if the user is not logged in. However the filter doesn't seem to be used. Why?
require_login is defined in app/helpers/sessions_helper.rb. So it is not a helper for my controller UsersController.
How does UserController know to use the function from sessions_helper.rb? It seems like I should be more specific: before_action "session/require_login".
The controller in users_controller.rb:
class UsersController < ApplicationController
before_action :signed_in_user
def index
end
end
The helper function in sessions_helper.rb:
def require_login
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in." unless signed_in?
end
end
You're following Michael Hartl's tutorial? Helpers in /app/helpers designed for view logic, not for controller code.
However, to get the helper included into your controllers you can use include SessionsHelper.
Reference: http://ruby.railstutorial.org/chapters/sign-in-sign-out#code-sessions_helper_include
before_filter can only call controller method, not helper.
You need to move the helper require_login from helper to UsesController or its parent say ApplicationController.
If you still want to use require_login as a helper in view, you can expose it from controller by helper_method
class UsersController < ApplicationController
before_fitler :require_login
helper_method :require_login
def require_login
# code
end
end

Resources