error: Too many redirects - ruby-on-rails

I'm using devise and trying the next following:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :is_worker
def is_worker
if user_signed_in?
#email = current_user.email
if #email && Worker.find_by_email(#email).nil?
redirect_to '/tasksadmins'
else
redirect_to '/workers'
end
else
redirect_to '/users/sign_in'
end
end
end
when I try to enter the site: localhost:3000/tasksadmins, I got:
Oops! It was not possible to show this website
The website at http://localhost:3000/tasksadmins seems to be unavailable. The precise error was:
Too many redirects
It could be temporarily switched off or moved to a new address. Don't forget to check that your internet connection is working correctly.
How can I fix it please?

before_filter is applied to every single request. That's why it's redirecting again and again.
You might want to only filter specific actions:
before_filter :is_worker, only: :index
Another solution would be to check wether a redirect is necessary in #is_worker:
redirect_to '/workers' unless request.fullpath == '/workers'
EDIT:
Another way would be to skip the before filter for the target actions of your redirects. Example:
class WorkersController < ApplicationController
skip_before_filter :is_worker, only: :index
# …
end

In my case:
users_controller.rb
before_action :logged_in?, only: :new
def new
#user = User.new
render layout: "session"
end
and
application_controller.rb
def logged_in?
redirect_to users_new_url unless current_user.present?
end
When I was trying to redirect to the 'users/new' page,same error occurred.
This is just because I'm trying to redirect to the 'users/new' page and "def logged_in?" is also redirecting to the same page.
Then I changed the application_controller.rb code like this:
def logged_in?
redirect_to root_url unless current_user.blank?
end
Error_Resolved.

Related

the AbstractController::DoubleRenderError cannot be fixed with "redirect_to and return"

I got this error today when I tried to use some helper methods for the users controller:
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and
at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need
to do something like "redirect_to(...) and return".)
I put this following helpers in application_controller.rb :
class ApplicationController < ActionController::Base
def current_user
User.find_by :id=>session[:user_id]
end
def log_in?
!!session[:user_id]
end
def log_in_first
if !log_in?
session[:error]="You have to log in first to continue your operation"
redirect_to("/login") and return
end
end
def correct_user?
if !(current_user.id.to_s==params[:id])
session[:error]="You have no right to do this operation."
redirect_to "/"
return
end
end
end
and here is the user_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id]=#user.id
redirect_to user_path(#user)
else
render 'new'
end
end
def show
log_in_first
#user = User.find_by id: params[:id]
correct_user?
if #user
render 'show'
else
redirect_to '/login'
end
end
private
def user_params
params.require(:user).permit(:name,:password,:email,:email_confirmation)
end
end
As you can see I tried to use both return and and return in log_in_first and correct_user?to fix the problem but it still doesn't work. Does anyone have any ideas?
The problem is in the show action, log_in_first redirects then the show action does whatever it wants, which is redirect or render. This is causing the error.
A better solution is to use before_action for your authentication and authorization and just let the user controller actions do their thing. Something like the below.
class ApplicationController < ActionController::Base
def current_user
User.find_by :id=>session[:user_id]
end
def log_in?
!!session[:user_id]
end
def authenticate_user!
if !log_in?
session[:error]="You have to log in first to continue your operation"
redirect_to("/login")
end
end
def authorize_user!
unless current_user&.id.to_s==params[:id]
session[:error]="You have no right to do this operation."
redirect_to "/"
end
end
end
class UsersController < ApplicationController
before_action :authenticate_user!, only: [:show]
before_action :authorize_user!, only: [:show]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
session[:user_id]=#user.id
redirect_to user_path(#user)
else
render 'new'
end
end
def show
#user = User.find_by id: params[:id]
render 'show'
end
private
def user_params
params.require(:user).permit(:name,:password,:email,:email_confirmation)
end
end

How identify a user session ? Rails

i have this routes:
Rails.application.routes.draw do
root 'login#new'
get '/home/inicio', to: 'home#index'
scope '/login' do
get '/acesso', to:'login#new'
post '/acessorecebendo', to:'login#create', as:'user'
get '/sair', to:'login#destroy'
end
resources :login
resources :home
resources :produtos
resources :fornecedors
end
the Login controller:
class LoginController < ApplicationController
protect_from_forgery
def new
if session[:user]
#user = User.find(session[:user])
end
end
def destroy
reset_session
redirect_to "/login/acesso", notice: "Você foi deslogado"
end
def create
user = User.validate(login_params[:email], login_params[:senha])
if user
session[:user] = user.id
redirect_to "/home/inicio", notice: "login feito com sucesso"
else
redirect_to "/login/acesso", notice: "Dados incorretos"
end
end
private
def login_params
params.require(:login).permit(:email, :senha)
end
end
The home controller:
class HomeController < ApplicationController protect_from_forgery with: :exception
def new
#user = User.find_by(id: session[:user]) end
def index
#produtos = Produto.all
render 'inicio' end
def show
if session[:user]
#user = User.find(session[:user])
end end end
I'm getting an error on the Home view (new.html.erb):
<header>
<h2>Bem-vindo <%= #user.nome %></h2>
<nav>
undefined method `nome' for nil:NilClass
Why i have some problems with the session? I can do the login and i wanna see the user informations of this session on the redirected page, like if i can pass the #user variable assigned on the login action to the home controller to use it.
This is happening because your #user is being set only in index and show, but you are trying to reference it from the new action.
Consider moving this logic to a before_action
class HomeController < ApplicationController
before_action if: ->{ session[:user] } do
#user = User.find_by(id: session[:user])
end
end
If this controller needs to assume that #user is present, you should also have a before_action that handles the case of a missing user account. I usually put this behavior into a AuthenticatedController class and inherit from it where needed.
User.find is not optimal here, because it will throw an exception if no record is found.

Setting up logging out...is there a way to check if a controller action contains a before_action

I have a before_action :logged_in_user in my controller which redirects to the login_path if there is no current_user.
I am struggling with the logic of how to setup logout (destroy a session) in my app.
If a user is on a page where they are not required to be logged_in?, I want the logout just to redirect_to :back (stay on that page) since it does not effect the current page viewing.
If they are on a page that requires that they are logged_in?, I want them to be redirect_to :root_url, because otherwise they will be redirect_to the login_path which is awkward since they just logged_out.
So basically in pseudo code I want to do the following:
redirect_to :back
unless :back controller:action >> before_action :logged_in_user
then redirect_to root_url
SessionsController
def destroy
destroy_location
log_out if logged_in?
redirect_logout
end
def destroy_location
path = ["/feed", "/friends", "/saved_articles", "/favorites"]
if path.any?{|word| URI(request.referrer).path == word }
session[:exit] = root_url
end
end
def redirect_logout
redirect_to(session[:exit] || :back)
session.delete(:exit)
end
This works rather nicely!

How to not apply before_filter for root route in rails?

I have a before_filter called check_login that looks something like this:
def check_login
if not session[:user_id]
flash[:error] = "Please log in to continue"
redirect_to login_path
end
end
I then put this before_filter in my application controller, and then exclude it in my login controller (with skip_before_filter :check_login)
The problem is that when the user hits the homepage for the first time (i.e. just localhost:3000), it will redirect them to the login page with the flash[:error] message displaying. However, for the homepage, I just want to show the login form. What's the cleanest way to handle this 'special-case'? I thought about putting the skip_before_filter in the controller that handles the homepage, but I didn't think this was very DRY, since if I change the homepage in the routes file, I'll have to also change the location of the skip_before_filter.
Thanks!
You can add some action in your filter
class LoginController < ApplicationController
skip_before_filter :check_login, :only => [:login]
def login
end
end
And in Application Controller, "blank?" check on presence and nil. It useful
def check_login
if session[:user_id].blank?
flash[:error] = "Please log in to continue"
redirect_to login_path
end
end
You can add named action for your homepage:
class StaticPagesController < ApplicationController
def home
end
end
And then check the current action in your callback:
def check_login
if not session[:user_id]
flash[:error] = "Please log in to continue" unless params[:action] == "home"
redirect_to login_path
end
end

before_filter doesn't seem to "kick in"

I'm trying to get before_filter to work on the actions that requires the user to be logged in, however something must be wrong because it's not.
I use a helper file called 'session_helper.rb' for login/logout as well as for checking if the user is logged in (signed_in?). That works fine if used inside an action or in the view, however while using it with the before_filer it's not working. If I log out the user and try to access '/projects/new' it's possible to do that, while it shouldn't be.
What am I doing wrong?
project controller:
class ProjectsController < ApplicationController
before_filter :signed_in?, :except => [:index] // <-- doesn't prevent e.g. the action "new" to be executed
def new
#project = Project.new
#users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))
end
def index
#projects = Project.all
if signed_in? // <-- works as it should
#users_projects = Project.where(:user_id => current_user.id)
end
end
... other actions ...
end
sessions_helper.rb
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
So, before_filter is a slightly misleading name. It is not really a filter. It isn't that it'll filter out the other actions and prevent them occurring if you return a falsey value, and allow them if you return a truthy one. It's really a way of calling a method before anything else. Think of it as 'before calling the action that the route has triggered, call the following method'.
Indeed, in Rails 4 they are renaming before_filter to before_action and that should alleviate the confusion moving forward.
You're just returning T/F from signed_in? So it's checking that and moving on, as you haven't told it to do anything special based on the results of that check.
So rather than calling signed_in? Something like this would work:
before_filter :authorize, :except => [:index]
def authorize
redirect_to login_url, alert: "Not authorized" if !signed_in?
end
Hop that helps.
I've always seen the before_filter raise an exception or redirect to another page when there is no current login. I am not sure that returning false will prevent the page from rendering.

Resources