Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devise and stored_location_for: how do you store the return location?

I have a page whose path is (e.g.) /premises/92 on which I'm displaying "please [log in] or [register] for additional information" if the user is not logged in, and I want devise to return that same /premises/92 page after the user logs in.

I've read other posts and I think I understand how devise's stored_location_for is supposed to work. In theory, I could put something like this in my ApplicationController:

def stored_location_for(resource)
  if (r = session[:return_to])
    session[:return_to] = nil
    r
  else
    super
  end
end

My question is: how / where do I set up session[:return_to]?

I want to set session[:return_to] only if the user clicks on [log in] or [register], but what's the best way to do that?

  • Decorate the links with JavaScript? That could work, but seems heavy-handed.
  • Set it in the Premises Controller before rendering the page? That doesn't seem right: what if the user doesn't click on the [log in] or [register] links? Then I have session[:return_to] set to some odd value which might trip me up if the user logs in from some other page.
  • Add a ?return_to=/premises/92 query string to the [log in] and [register] links, and detect that in the RegistrationsController and SessionsController and use that info to set up session[:return_to]? That seems like it would work, but also heavy-handed.

None of these smell right. What's the generally accepted technique for setting up state for stored_location_for?

like image 547
fearless_fool Avatar asked May 17 '11 08:05

fearless_fool


2 Answers

Devise use

session["#{scope}_return_to"]

So you can use session["user_return_to"] if your model for authentication is User.

like image 147
rorra Avatar answered Nov 16 '22 16:11

rorra


I found this whole devise redirect thing quite confusing.

Where @rorra says Devise uses session["#{scope}_return_to"], he means that Devise default after_sign_in_path_for(resource) will use that variable through the method stored_location_for(resource).

So you should save the location you want to store in the variable session["#{scope}_return_to"], which will usually be session["user_return_to"]. To do this place the following in your application_controller.rb:

after_action :store_location

def store_location
  # store last url - this is needed for post-login redirect to whatever the user last visited.
  if (request.fullpath != "/users/sign_in" &&
      request.fullpath != "/users/sign_up" &&
      request.fullpath != "/users/password" &&
      request.fullpath != "/users/sign_out" &&
      !request.xhr?) # don't store ajax calls
    session["user_return_to"] = request.fullpath 
  end
end

In some cases you will not need to define an after_sign_in_path_for(resource) method as devise's default method will do all the redirects for you and if their is no redirect url available you will be redirected to the resource root path (usually user root path) and if that doesn't exist you will be redirected to the root path. If however, you would like to customise where the user is sent if there is no redirect url available, add the following to your application_contorller.rb (and change root_path accordingly):

def after_sign_in_path_for(resource)
  stored_location_for(resource) || root_path
end
like image 9
Jeremy Lynch Avatar answered Nov 16 '22 17:11

Jeremy Lynch