Search code examples
ruby-on-railsrubydevise

Using devise login as root calls separate root in an infinite loop and causes " url redirected you too many times"


After logging the user in, then closing the page and reopening the page is redirected too many times. The rails terminal shows an infinite call of the following two routes to each other, but I can't figure out why this is happening. Any help would be greatly appreciated.

Started GET "/users/sign_in" for xxx.xxx.xxx.xx at 2019-07-20 20:52:11
Started GET "/" for xxx.xxx.xxx.xx at 2019-07-20 20:52:12

Changing the root from the devise login fixes the issue, but this isn't desirable.

routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: {sessions: "sessions"}
  root :to => redirect("/users/sign_in")
  post 'pindex', to: 'locker#index'
  get 'view',   to: 'locker#view'
  post 'view', to: 'locker#many_new'
  match 'sort/:type', to: 'locker#sort', :via => :get, :as => :sort
  resources :locker
 end

sessions_controller.rb

 class SessionsController < Devise::SessionsController
  def new
    super
  end

  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_navigational_format?
    sign_in(resource_name, resource)
    if !session[:return_to].blank?
     redirect_to session[:return_to]
      session[:return_to] = nil
    else
      respond_with resource, :location => locker_index_path
     end
   end
 end

new.html.erb

 <%= form_for(resource, as: resource_name, url: 
 session_path(resource_name)) do |f| %>
    </span>
     <%= f.email_field :email,
     class: "form-control", 
     placeholder: "Email Address",
     required:"required"%>  
    </span>
    <%= f.password_field :password, 
      class: 'form-control',
      placeholder: "Password",
      required:"required"%> 
     <%= f.submit "Log In", class: "btn btn-primary btn-block btn-lg"%>
 <%end%>

Solution

  • Looking at the source code of Devise you can see that in SessionsController they call require_no_authentication before new.

    prepend_before_action :require_no_authentication, only: [:new, :create]
    

    And this method redirects to after_sign_in_path_for(resource) if the user is signed in. after_sign_in_path by default is root_path which you redirect to sessions#new. So here is your infinite loop.

    if authenticated && resource = warden.user(resource_name)
      flash[:alert] = I18n.t("devise.failure.already_authenticated")
      redirect_to after_sign_in_path_for(resource)
    end
    

    To solve it you should override after_sign_in_path_for in your SessionsController with something else than root_path:

    def after_sign_in_path_for(_resource_or_scope)
      locker_index_path # or anything you want
    end