5

After a successful login via Devise, how can I redirect the user back to the page they were on?

I've read and searched a lot already, and I understand that I need to define after_sign_in_path_for. I've done this and its working correctly, what I'm having trouble with is understanding how the previous page is stored, and how to call it correctly.

I have this in my sessions controller:

def after_sign_in_path_for(resource)
    return request.env['omniauth.origin'] || session[:user_return_to] || root_path
end

I've also tried

...
return request.env['omniauth.origin'] || stored_location_for(resource) || root_path
...

I don't think I am understanding how to store the location, as the user is redirected back to the root path if they click to log in.

A sign in can be initiated in two ways. Either (a) the user attempts to access a restricted view (i.e. before_filter :authenticate_user!..., in which case they are redirected and prompted to login. Or (b) the user clicks a sign in link which is available on every page if the user is not logged in.

(a) seems to be working. (b) is not. I guess I need to store the current location to session when the user clicks the log in link.

How do I do this? Or, where is a good source of information that would help me understand this.

Thanks!

4

4 回答 4

9

You can get the previous url using request.referrer as is explained in this SO question: How to redirect to previous page in Ruby On Rails?

于 2012-05-17T06:51:25.027 回答
4

Use

redirect_to request.referrer
于 2012-05-17T06:53:09.300 回答
2

Heads up: The code should go in your application_controller.rb, not sessions controller.

How it works is that newer versions of Devise automatically store the initial page the user tried to visit (before getting redirected to sign in).

That can be accessed by using the devise helper: stored_location_for(resource)

What you add to your application controller is something like this:

def after_sign_in_path_for(resource)
  stored_location_for(resource) || users_dashboard_path
  # replace users_dashboard_path by whichever route you want to redirect to after login - default is root_path
end

After a successful sign in, Devise will automatically run your method from application controller instead of it's own (overriding it).

For a more complex example, here's one from the Devise team:

def after_sign_in_path_for(resource)
  stored_location_for(resource) ||
    if resource.is_a?(User) && resource.can_publish?
      publisher_url
    else
      super
    end
end

I hope this answer helps anyone searching how to do this with newer versions of devise.

于 2016-05-20T19:12:45.407 回答
0

Here is another approach. I am enabling this "return to" feature only on certain links (via the continue URL parameter). In the example below I am taint checking params[:continue] prior to assigning it to session[:continue] in the after_action - though perhaps that is unnecessary if you have authorization in place. Finally, in the after_sign_in_path_for method override I delete session[:continue] meanwhile using it (as it is not needed afterwards) - deleting the key/value pair returns the value if the key matches, otherwise nil is returned, in which case the statement falls back on root_path.

app/views/journal/show.html.erb

<%= link_to 'sign in', new_user_session_path(continue: journal_url(@journal)) %> or
<%= link_to 'sign up', new_user_registration_path(continue: journal_url(@journal)) %>

app/controllers/application_controller.rb

after_action :store_location

def store_location
    if params[:continue] =~ /\/(journal\/[0-9]+|foo|bar)\z/ # safelist
        session[:continue] = params[:continue]
    end
end

def after_sign_in_path_for(resource)
    session.delete(:continue) || root_path
end
于 2014-03-06T20:58:45.033 回答