Redirect to log in page if user is not authenticated with Devise
Asked Answered
G

5

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).

Godliman answered 9/5, 2014 at 2:16 Comment(0)
F
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)

Fertile answered 10/5, 2014 at 18:53 Comment(8)
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.Godliman
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 . Appreciate the help!Stratiform
in Rails 5, replace match '/sign-in' with get '/sign-in'Sliest
always use login_url rather than login_path when redirectingThrombus
This returns 302 status code, can I return 403 status code and handle redirect in browser javascript ?Boman
@Thrombus Could you elaborate?Assr
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 :-)Thrombus
The solution on Devise wiki is recommended over this override github.com/heartcombo/devise/wiki/…Otic
D
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.

Dispersoid answered 22/2, 2015 at 4:30 Comment(1)
Correct answer if using devise. No need to rewrite unless you want to customize.Brooch
R
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.

Rooseveltroost answered 22/7, 2014 at 23:49 Comment(0)
N
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
Neptune answered 9/5, 2014 at 3:16 Comment(2)
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.Godliman
Thanks for linking the Devise documentation. That should be the way to go.Wilone
W
-6

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

Wharfinger answered 9/5, 2014 at 5:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.