19

What I'm trying to do

I want to send a user to the registrations#new page if they aren't logged in.

After you enter login info and click submit, I want you to be sent to the registrations#show page.

What is happening

It sends you to the registrations#new page when you're not logged in (correct so far). But when you submit the login form, it sends errors out with a redirect loop. The server's output is just this block repeated over and over:

Started GET "/" for 127.0.0.1 at 2013-09-25 02:31:59 -0400
Processing by RegistrationsController#new as HTML
  User Load (0.7ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 8 ORDER BY "users"."id" ASC LIMIT 1
Redirected to http://lvh.me:3000/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.7ms)

I can't seem to figure it out. It does log you in, as I can see that by manually navigating to a different page, but the authenticated root path is not working correctly. I've tried a few different combinations in my routes file and can't seem to get it. The code I'm using is based off of this thread

My code

In my application controller I have before_filter :authenticate_user!

My routes file:

devise_for :users, :controllers => {
  :registrations => "registrations"
}

devise_scope :user do
  root to: "registrations#new"
end

authenticated :user do
  root to: "registrations#show", :as => "profile"
end

unauthenticated do
  root to: "registrations#new", :as => "unauthenticated"
end
Tom Prats
  • 7,364
  • 9
  • 47
  • 77

3 Answers3

26

First, you should customize Devise::RegistrationsController (you can add file app/controllers/registrations_controller.rb)

And see prepend_before_filter on devise registrations_controller.rb

prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ]
prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy]

Add show action to prepend_before_filter :authenticate_scope!

registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController
  prepend_before_filter :require_no_authentication, :only => [ :new, :create, :cancel ]
  prepend_before_filter :authenticate_scope!, :only => [:edit, :update, :destroy, :show]

  # GET /resource/sign_up
  def new
    super
  end

  # POST /resource
  def create
    super
  end

  # GET /resource/edit
  def edit
    super
  end

  def update
    super
  end

  # DELETE /resource
  def destroy
    super
  end

  def show
  end


  protected

  def after_sign_up_path_for(resource)
    after_sign_in_path_for(resource)
  end

end

Also copy the view of devise registration (edit and new template) to /app/views/registrations/ and You can make a file show.html.erb in /app/views/registrations/ folder for a profile page.

For routes of devise looks like :

devise_for :users, :skip => [:registrations]

devise_for :users, :controllers => {
  :registrations => "registrations"
}

authenticated :user do
  devise_scope :user do
    root to: "registrations#show", :as => "profile"
  end
end

unauthenticated do
  devise_scope :user do
    root to: "registrations#new", :as => "unauthenticated"
  end
end

Last, you to set a "path" in after_sign_in_path_for(resource) and after_sign_out_path_for(resource_or_scope) at file application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery

  private

   def after_sign_in_path_for(resource)
     # After you enter login info and click submit, I want you to be sent to the registrations#show page
     profile_path
   end
   def after_sign_out_path_for(resource_or_scope)
     new_user_session_path
   end
end

Note: I have tried this (to make sample apps), and it works. See log when sign in here, and log sign out here

rails_id
  • 8,120
  • 4
  • 46
  • 84
  • cool ill try this tomorrow. did you try it with rails 4 apps? – Tom Prats Oct 09 '13 at 04:44
  • 1
    great work. all i did was modify my routes file to be like yours! the devise_scope within authenticated and/or unauthenticated. I then added the rest of my signed in routes within the authenticated devise_scope block – Tom Prats Oct 12 '13 at 02:32
  • Thanx so much. This saved my day. Using prepend_before_filter :require_no_authentication, only: [:edit, :update] prepend_before_filter :authenticate_scope!, except: [:edit, :update] – hisa_py Jan 09 '15 at 02:48
8

The redirect to registration#new is default so all you need to do is this (in your route file):

devise_for :users, :controllers => {
  :registrations => "registrations"
}

devise_scope :user do
  root to: "registrations#show" # This is the root path of the user when you are logged in
end

unauthenticated do
  root to: "registrations#new", :as => "unauthenticated"
end

# I dont't think this part is neccesary... Try if it works without
authenticated :user do
  root to: "registrations#show", :as => "profile"
end
jokklan
  • 3,520
  • 17
  • 37
  • but this doesn't use the `authenticated` and `unauthenticated` methods I saw mentioned – Tom Prats Oct 11 '13 at 07:13
  • Sorry forgot `unathenticated`, but i don't think `authenticated` is neccesary when you have `devise_scope` with `root`. But i'll will try to test more when i have time :). – jokklan Oct 11 '13 at 08:19
  • doesnt this look exactly like mine in the question? – Tom Prats Oct 12 '13 at 02:32
  • No you had `root to: "registrations#new"` in the `devise_scope` block, which properly was the main reason for your problem. – jokklan Oct 14 '13 at 09:23
2

Do not use routes to do the jobs belonging to controller.

To redirect an user to certain page after signing up, use Devise built-in after_sign_up_path_for and override it.

class ApplicationController
  def after_sign_up_path_for(resource)
    faked_user_profile_path(resource)
  end
end

For routes, I'm not very aware of all of them except devise_for part. But for the redirecting feature, this overriding should be enough.

Billy Chan
  • 24,625
  • 4
  • 52
  • 68
  • I'll try this, but according to the devise documentation it was the way to do it... – Tom Prats Sep 25 '13 at 14:32
  • 1
    TMP, I have not read full Devise wiki and am not aware of that part, so my last statement may be inaccurate, I'll delete that. However, to implement the feature you requested, the method overridding should be enough and simplest. – Billy Chan Sep 25 '13 at 14:37
  • for some reason I'm still getting the redirect loop, I have a feeling the `after_sign_up_path_for` isn't working and it's still sending it back to root – Tom Prats Sep 26 '13 at 00:26
  • nevermind, you were exactly right, i just also had to define `after_sign_in_path_for` because signing up and in both need to go somewhere. I'm going to hold off on accepting this because I still want to know the more devise way to do it with `authenticated :user do` – Tom Prats Sep 26 '13 at 00:31
  • Update: second best answer is actually `signed_in_root_path` but still would like `authenticated` root answer – Tom Prats Sep 26 '13 at 01:11