可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 (i.e /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.
回答1:
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 (e.g., /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.
回答2:
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
回答3:
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
回答4:
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