I'm having a bit of a noob issue. I wanted to get devise to redirect to the last page the user visited. So I did the following...
def after_sign_in_path_for(resource)
request.referer
end
Works great...except if the user is actually logging in through the original form which causes a redirect loop.
I tried
def after_sign_in_path_for(resource)
if (request.referer == "/users/sign_in")
:pages_home
else
request.referer
end
end
But thats not working, most likely because I have no idea what request.referer is actually returning when it encounters the original user login page (www.example.com/users/sign_in).
Any ideas?
tldr; Using devise, I want to redirect to the page logged in from (ie /blog/4) unless the page is /users/sign_in
SOLVED:
Matchu was right. The request.referer was returning the domain as well...
http://example.com/users/sign_in
(note: no www prefix)
I'm still interested in an alternative to request.referer if its an insecure or inefficient way.
Don't redirect to referrers - it's generally a bad idea.
Instead, pass a next
value across in the query-string or form-data. Perhaps use something like:
def after_sign_in_path_for(resource)
params[:next] || super
end
When a user tries to visit a page requiring authentication (eg, /admin/posts/3/edit
) the authentication before_filter
issues a redirect_to new_session_url(:next => request.path)
. Then code up the login action and view to preserve the :next
query-string parameter.
How about this:
def after_sign_in_path_for(resource)
sign_in_url = url_for(:action => 'sign_in', :controller => 'users', :only_path => false, :protocol => 'http')
if (request.referer == sign_in_url)
super
else
request.referer
end
end
I took Justice's answer and changed it to use sessions instead.
As far as I can see, sessions are simpler then adding the url as param, but they might behave unexpected when a user is browsing a site in multiple tabs, for example. Using sessions is less RESTfull, but simpler and cleaner.
When using CanCan, setting the redirect-path can be done in a central place: the place that handles the "access denied" exceptions:
rescue_from CanCan::AccessDenied do |exception|
if current_user.nil?
session[:next] = request.fullpath
puts session[:next]
redirect_to new_user_session_path, :alert => exception.message
else
render :file => "#{Rails.root}/public/403.html", :status => 403
end
end
But you can set this anywhere, actually:
def edit
if current_user.roles[:moderator].nil?
session[:next] = "/contact"
redirect_to new_user_session_path, :alert => "please contact the moderator for access"
end
# ...
end
Then, in ApplicationController
, you can re-use that session value. Make sure to remove it too, though.
def after_sign_in_path_for(resource)
path = ''
if session[:next]
path = session[:next]
session[:next] = nil
else
path = super
end
path
end
Here is my code to rescue_from
CanCan.
rescue_from CanCan::AccessDenied do |exception|
if current_user.nil?
session[:next] = request.fullpath
puts session[:next]
redirect_to login_url, :alert => "You have to be logged in to continue"
else
#render :file => "#{Rails.root}/public/403.html", :status => 403
if request.env["HTTP_REFERER"].present?
redirect_to :back, :alert => exception.message
else
redirect_to root_url, :alert => exception.message
end
end
end
What it does: - if the user is not logged in, it redirects to login page - if the user is logged in, but do not have abilities to see the action, it redirects either back or to the root page with alert flash message
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.