可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Here I'm using Devise Gem for authentication. If someone want to open page without login then it redirect to sign_in page and after signed in it back to the page which user try to open.
I use Redirect loop with Devise after_sign_in_path_for link for my problem but it does not work for me.
def after_sign_in_path_for(resource)
params[:next] || super
end
It doesn't redirect back me to the page which I want to open.
for example: If I want to open "127.0.0.1:3000/post/2/edit", it doest not back to this page after signed in.
回答1:
The best resource to seek is the official repo/wiki/issues, and then SO. The answer you found is out of date.
Here is the answer:
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update
Just add the following in ApplicationController for versions devise > 3.2.1:
# This example assumes that you have setup devise to authenticate a class named User.
class ApplicationController < ActionController::Base
before_action :store_user_location!, if: :storable_location?
# The callback which stores the current location must be added before you authenticate the user
# as `authenticate_user!` (or whatever your resource is) will halt the filter chain and redirect
# before the location can be stored.
before_action :authenticate_user!
private
# Its important that the location is NOT stored if:
# - The request method is not GET (non idempotent)
# - The request is handled by a Devise controller such as Devise::SessionsController as that could cause an
# infinite redirect loop.
# - The request is an Ajax request as this can lead to very unexpected behaviour.
def storable_location?
request.get? && is_navigational_format? && !devise_controller? && !request.xhr?
end
def store_user_location!
# :user is the scope we are authenticating
store_location_for(:user, request.fullpath)
end
end
And then to redirect after signing in, you have to override this method:
def after_sign_in_path_for(resource_or_scope)
stored_location_for(resource_or_scope) || super
end
回答2:
You don't need all this code. Devise (as the latest versions) already saves the location for you.
Just use this:
def after_sign_in_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || root_url
end
This will redirect user to the latest omniauth.source, or the stored_location and is last case, the root url.
I thought I was required to create that method, but Devise already does it.
Source: https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in
回答3:
As of Devise 4, it worked seamlessly for me:
Devise automatically redirects on sign in and sign up as long as you
store the location of the current page using devise's
store_location_for(resource)
. To do this, edit your
ApplicationController
in
app/controllers/application_controller.rb
. Add:
# saves the location before loading each page so we can return to the
# right page. If we're on a devise page, we don't want to store that as the
# place to return to (for example, we don't want to return to the sign in page
# after signing in), which is what the :unless prevents
before_filter :store_current_location, :unless => :devise_controller?
private
# override the devise helper to store the current location so we can
# redirect to it after loggin in or out. This override makes signing in
# and signing up work automatically.
def store_current_location
store_location_for(:user, request.url)
end
Add the following to the ApplicationController
to make sign out
redirect:
private
# override the devise method for where to go after signing out because theirs
# always goes to the root path. Because devise uses a session variable and
# the session is destroyed on log out, we need to use request.referrer
# root_path is there as a backup
def after_sign_out_path_for(resource)
request.referrer || root_path
end
回答4:
As pointed out in the official documentation, the simpler solution would be to simply add this to your application_controller.rb
:
class ApplicationController < ActionController::Base
private
# If your model is called User
def after_sign_in_path_for(resource)
session["user_return_to"] || root_path
end
Important Note (Which I also overlooked) is that for this to work you will need to call authenticate_user!
method, available by default in Devise, in your controller's before_action:
. This will call store_location_for
available out of the box in Devise, and the rest is handled by the above code in the application_controller.rb
, thus eliminating the need to rewrite code to save requesting url.
回答5:
Some of the other solutions here may not work if your login form has its own page, as opposed to, e.g., a login form in the header of every page. After logging in, the user needs to go back two pages, not just one.
Devise has a nice How To on Redirecting back to the current page after sign in, sign out, update, from which the code below comes.
Storing the original URL in the session is the best option. In addition to solving the above problem of going back two pages, "Many browsers do not send [the request.referer
] header. Therefore the only robust cross-browser way to implement this functionality is by using the session."
When storing URLs in the session, it's important not to store the URL for any POST, PUT, or DELETE request, nor any XHR request, i.e. nothing to which the user can't actually be redirected.
Note that after signing out, the user's session is destroyed, so the stored URL is gone. In this case, the user can be sent back to request.referer
. This seems acceptable since most websites have a sign out link on every page, so returning to the referrer will actually work.
class ApplicationController < ActionController::Base
before_action :store_user_location!, if: :storable_location?
before_action :authenticate_user!
private
def storable_location?
request.get? && is_navigational_format? && !devise_controller? && !request.xhr?
end
def store_user_location!
store_location_for(:user, request.fullpath)
end
def after_sign_in_path_for(resource_or_scope)
stored_location_for(resource_or_scope) || super
end
def after_sign_out_path_for(resource_or_scope)
request.referrer || super
end
end
回答6:
I has the same doubt and found this, try it too
def after_sign_in_path_for(resource_or_scope)
session.fetch 'user_return_to', admin_root_path
end
回答7:
gem 'devise', '~> 4.4.0'
Create sessions_controller.rb: class SessionsController < Devise::SessionsController
Add the following (modifying the regex if your login url isn't /users)
def before_login
session[:previous_url] = request.fullpath unless request.fullpath =~ /\/users/
end
def after_login
session[:previous_url] || root_path
end
Notice that this does not work if you've got /users/dashboard or other locations under /users. Might want to get more specific with the regex.
回答8:
There's no need to define new methods in Devise 4.4.3. Just call method DeviseController#after_sign_in_path_for
directly.
Code like this:
class YourController < DeviseController
# ...
if manager.valid_password? params[:manager][:password]
sign_in manager
# call this method directly , if your controller extends DeviseController
redirect_to after_sign_in_path_for(manager), notice: 'welcome!'
end
Also, if you are using your customized login method and using DeviseController, you must NOT use this code:
# this method will login automatically, in most cases this method is
# useless and misleading.
prepend_before_action :allow_params_authentication!, only: :create