Devise Resetting Session On Login - ruby-on-rails

I've got the following defined in my application_controller.rb file:
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end
def store_location
session[:return_to] = request.url
end
def after_sign_in_path_for(resource)
r = session[:return_to] || user_root_url
session.delete(:return_to)
r
end
I'm trying to send a user back to the place they came from before the sign_in, or, if no location is saved, send them to their root page.
I call this in one of my controllers:
if current_user.nil?
store_location
redirect_to home_login_url, alert: "You must be logged in to purchase subscriptions"
return
end
I stepped through the debugger and watched the session[:return_to] get set, but after I log on and the after_sign_in_path_for(resource) is called, session[:return_to] is null.
How can I persist the return_to variable across a login?
I'm running Rails 3.2.1 and Devise 2.1.2

Turns out I was overwriting Devise's entry in my hash. I think :return_to is what Devise uses. I ended up implementing this completely differently, but look for name conflicts if you have a problem

Related

Friendly forwarding after login doesn't work after adding friendly_id to the user model

The core of my app is build from Michael Hartl's rails tutorial. Recently I changed the User DB so the name column is named username and I also added in friendly_id for prettier URLs. I updated everywhere I could find in accordance with these changes and everything works smoothly except for friendly forwarding after a user logs in. e.g. if a non logged in user visits a user edit page they are taken to the login page, after they login they should be taken to their edit page. But instead it just logs them in and stays on the login page.
I cant see anywhere that would need changing so it works again and from what I can see it should work
session controller
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_back_or user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
user controller
before_action :correct_user, only: [:edit, :update]
before_action :logged_in_user, only: [:edit, :update]
def edit
end
private
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
def correct_user
#user = User.friendly.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
application controller
def redirect_back_or(path)
redirect_to request.referer || path
end
private
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "You gotta login first!"
redirect_to login_url
end
end
session helper
# Redirects to stored location (or to the default).
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.url if request.get?
end
Anyone know where the problem might lie?
Update
after chatting with #vishal the redirect is done from the application controller redirect_back_or method
def redirect_back_or(path)
redirect_to request.referer || path
end
If I change it to
def redirect_back_or(path)
redirect_to root_path || path
end
I am taken to the root path so I know this line os most likely the culprit.
In-between it working and not working I added the mailboxer gem for private messages, changed the Users db name to username and added friendly_id to the username column. Maybe something there might stand out to you as a cause for it stop working.
In your application controller, change redirect_back_or(path) method to this.
def redirect_back_or(path)
redirect_to session[:forwarding_url] || path
session.delete(:forwarding_url)
end
You had redirect_to request.referer before which was responsible for redirecting you to the last url, that is, the login_url.
I have no idea why you're defining two different methods - 1 in ApplicationController & 1 in SessionsHelper - with the same name but different intended behaviors though.

Rails: redirect to previous page after login doesn't work

I am trying to redirect to the page from where I clicked login, but after logining in it doesn't redierect to previous page but stays on login page (although the user is already logged in).
Here is my code:
session_helper.rb
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end
def store_location
session[:return_to] = request.fullpath
end
end
sessions_controller.rb
class SessionsController < ApplicationController
include SessionsHelper
def new
end
def create
user = User.find_by_username(params[:session][:username])
if user && user.authenticate(params[:session][:password])
cookies.permanent[:remember_token] = user.remember_token
#redirect_to root_url,:notice => "Logged in!"
redirect_back_or user
else
flash[:error] = 'Invalid email/password combination' # Not quite right!
render 'new'
end
end
def destroy
cookies.delete(:remember_token)
#session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end
I also tried to write in create function in sessions_controller.rb
redirect_to request.referer
but it doesn't work.
Am I missing something?
Thanks for your help!
The problem happens at store_location.
Though you havn't said in question, I guess you probably put this method in before_filter. So, no matter GET or POST or other request, the request hit this filter at first and store location.
Now, in this case, actually the user has two requests. One is to #new by GET, and the other is to #create by POST. In the later, his last request to #new was recorded as the going back location. So you'll see you always go back to #new :)
The solution is to filter the location to be stored.
def store_location
disable_pattern = /\A\/user*/
session[:return_to] = request.fullpath unless request.fullpath ~= disable_pattern
end
This pattern could solve current problem but not exclusive. In practice you may see even JS/JSON requests has been recorded, so you may need to add more restrictions according to the specific case. For example, only apply before_filter on #show or #index, use white list, etc.
I think request.referer may not have worked because of a typo in the method. It should be request.referrer.

Check URL type for redirection in Rails

Using Rails 3.2. I have the following in my app:
# application_controller.rb
def store_location
session[:return_to] = request.url
end
def store_referrer_location
session[:return_to] = request.referrer
end
# user_sessions_controller.rb
def destroy
store_referrer_location if session[:return_to].blank?
current_user_session.destroy
flash[:success] = "Logout successful!"
redirect_back_or_default root_url
end
If I am at /places/2/edit, then I click logout, the session[:return_to] would store /places/2/edit and attempt to redirect back to /places/2/edit, which then redirects to /login again.
How can I detect if the request.url or request.referrer is from the edit action, it would just store the /places/2 only?
I'm thinking of using Regex to check for edit word after the ID, but there might be a cleaner way.
If you really need to be able to check such a thing on the request.referrer, a regex may be a good option:
request.url.gsub(/\/edit$/,'')
But if you are actually coming from the edit action, your session[:return_to] should not be blank as you should have done a call to store_location in your edit action.
In such a case, you would not need to check the request.referrer and, as Bigxiang suggested you may change the store_location method to make it store only the show path when you are in edit action
Example
# application_controller.rb
def store_location
session[:return_to] = action_name == 'edit' ? url_for(action:'show') : request.url
end

How to use both Devise and Doorkeeper gems?

I am building a web app (with an API too) that is using Devise gem for authentication and I also use Doorkeeper gem for authentication for the API part.
Problem is now that when I go to the URL for receiving the Oauth2 code (and login) I am redirected to the web app and not the client callback URL.
What I need to do is redirect to the web app when signing in normally and to the callback URL when using Oauth.
How can I do this? I am overwriting the Devise sessions controller but I do not know what to put into it.
This is my code:
def new
session[:return_to] = params[:return_to] if params[:return_to]
resource = build_resource
clean_up_passwords(resource)
end
def create
resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
if session[:return_to]
redirect_to session[:return_to]
session[:return_to] = nil
else
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
Problem is that Devise seems to ignore my redirect logic.
Please advice further.
Assuming your resource is user add session[:user_return_to] = request.fullpath to resource_owner_authenticator block
Example:
resource_owner_authenticator do
#raise "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
# Put your resource owner authentication logic here.
# Example implementation:
session[:user_return_to] = request.fullpath
current_user || redirect_to(login_url)
end
This worked for me, in ApplicationController (that Devise's controllers inherit from):
def store_location
# store last url as long as it isn't a /users path
session[:previous_url] = request.fullpath unless request.fullpath =~ /\/users/
end
def after_sign_in_path_for(_resource)
session[:previous_url] || root_path
end
And in the Doorkeeper initializer:
resource_owner_authenticator do
if user_signed_in?
current_user
else
session[:previous_url] = request.fullpath unless request.fullpath =~ /\/users/
redirect_to(new_user_session_path)
end
end
The idea is to remember the path you came from in a session cookie and then let Devise redirect there when it calls its own after_sign_in_path_for callback.
Documentation pointed out the resource_return_to session key, but this worked for me so I didn't examine anymore.

rails specify method for redirect_to

During a post for a new model, I am checking for authentication via Authlogic. There is a before_filter on the create request. It is calling require_user. After the user session has been successfully created, the redirect_back_or_default(default) method is called. The problem is, The request needs to be posted to the stored uri. I have tried to store the method and input it into the redirect_to however it isn't working. Any ideas?
# called before successful authentication with before_filter
def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end
def store_location
session[:return_to] = request.request_uri
session[:return_to_method] = request.request_method
end
# called after successful authentication
def redirect_back_or_default(default)
redirect_to((session[:return_to] ? session[:return_to] : default), :method => session[:return_to_method])
session[:return_to] = nil
session[:return_to_method] = nil
end
You can't redirect to a post action, only get actions.
You could store the post object for later processing after authentication, but you really don't want to do that.
Why not simply ask for authentication on the #new method, rather than (or in addition to) the #create? That way the user is authenticated before they fill in the form.

Resources