30

I'm using Devise with Ruby on Rails.

What is the recommended way to redirect unauthenticated users to the sessions#new page if they attempt to access a page that requires authentication?

Right now I get an error that says no route matches the one they attempt to access (leading to a 404 error in production).

Gdeglin
  • 12,432
  • 5
  • 49
  • 65

5 Answers5

73

Just simple add this method to application_controller.rb

  protected
  def authenticate_user!
    if user_signed_in?
      super
    else
      redirect_to login_path, :notice => 'if you want to add a notice'
      ## if you want render 404 page
      ## render :file => File.join(Rails.root, 'public/404'), :formats => [:html], :status => 404, :layout => false
    end
  end

And you can call this method on before_filter another controllers you want.

e.g :

class HomesController < ApplicationController
  before_filter :authenticate_user!
  ## if you want spesific action for require authentication
  ## before_filter :authenticate_user!, :only => [:action1, :action2]
end

Don't forget add login_path into routes.rb

devise_scope :user do
  match '/sign-in' => "devise/sessions#new", :as => :login
end

note : I always use this way when play with devise for my apps authentication.. (rails 3.2 and rails 4.0.1)

GeekToL
  • 1,815
  • 1
  • 24
  • 46
  • Thanks, that worked. I also realized I had set up my routes incorrectly -- I placed many of them in a "authenticated :user" block, that's why I was getting 404's trying to access them when logged out. – Gdeglin May 15 '14 at 23:44
  • Thanks. this has been working out great for me but has created some other problems. For instance, when I go to edit a user registration, I get an argument error (saying wrong number of arguments: 1 for 0) and pointing to `def authenticate_user!` line. Posted question here: [link](http://stackoverflow.com/questions/25170716/devise-ror-argument-error-when-editing-user-registration) . Appreciate the help! – orky Aug 07 '14 at 02:40
  • 2
    in Rails 5, replace match '/sign-in' with get '/sign-in' – V-SHY Jan 01 '17 at 06:23
  • always use **login_url** rather than **login_path** when redirecting – sekmo May 30 '17 at 15:26
  • This returns 302 status code, can I return 403 status code and handle redirect in browser javascript ? – vaibhavatul47 Aug 31 '17 at 06:37
  • @sekmo Could you elaborate? – Niek Sep 20 '17 at 08:57
  • When redirecting, it's more safer using the `_url` helper like `login_url`, `new_post_url` etc., since the URL contains the protocol as well. Try on the console running `app.login_url` and `app.login_path` :-) – sekmo Sep 21 '17 at 09:14
  • The solution on Devise wiki is recommended over this override https://github.com/heartcombo/devise/wiki/Redirect-to-new-registration-(sign-up)-path-if-unauthenticated – Sébastien Grosjean - ZenCocoon May 16 '20 at 17:52
29

You can do just like GeekTol wrote, or just put

before_action :authenticate_user!

in your controller.

In this case, devise uses the default authenticate_user! method, that will redirect to the "user_session_path" and use the default flash message.

It's not necessary to rewrite authenticate_user! method, unless you want to customize it.

imtk
  • 1,510
  • 4
  • 18
  • 31
  • Correct answer if using devise. No need to rewrite unless you want to customize. – ben May 02 '15 at 00:34
3

I thought you could just add: before_action :authenticate_user! to each controller that required the user to be logged in.

I'm a Rails beginner but I found this in my own searches and it works well in my application.

comphelp
  • 505
  • 1
  • 3
  • 12
2

You should refer to Devise's own How To: How To: Redirect to a specific page when the user can not be authenticated.

Another alternative I can think of is creating a routing Constraint wrapping your protected routes. You'd better stick to Devise's way, but here is an example:

#On your routes.rb
constraints(Constraints::LoginRequired) do
  get '/example' 
end

#Somewhere like lib/constraints/login_required.rb
module Constraints
  class LoginRequired
    def self.matches?(request)
      #some devise code that checks if the user is logged in
    end 
  end
end
Lucas Polonio
  • 1,003
  • 10
  • 8
  • Thanks for the reply. When it comes to the Devise How To that you linked to, it only provides instructions for Rails 3, and some of which don't apply to Rails 4. Even when attempting to account for the differences, it's not working for me. Will try your Constraint suggestion next. – Gdeglin May 09 '14 at 04:24
  • Thanks for linking the Devise documentation. That should be the way to go. – maxhm10 Oct 15 '15 at 19:38
-6

Add this code in your config/routes.rb devise_for :users and resources :users and you can generate devise in views.

Antony Mithun
  • 161
  • 1
  • 15