In my application, I have two different login forms from two controller which will both sign_in through the Devise::SessionsController, the problem is after successful sign in (or failure) I need to redirect to different pages that specific to the controller. How can I do this. I currently have this in my Devise::SessionsController, which
class SessionsController < Devise::SessionsController
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
return sign_in_and_redirect(resource_name, resource)
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
redirect_to dashboard_path
end
def failure
redirect_to index_path
end
end
In application controller
before_filter :store_location
def store_location
unless params[:controller] == "devise/sessions"
url = #calculate the url here based on a params[:token] which you passed in
session[:user_return_to] = url
end
end
def stored_location_for(resource_or_scope)
session[:user_return_to] || super
end
def after_sign_in_path_for(resource)
stored_location_for(resource) || root_path
end
If anyone is still looking for a work around. I was able to solve this by:
First, create a Sessions controller inheriting from Devise::SessionsController
class SessionsController < Devise::SessionsController
def new
get_pre_login_url(request.referer)
super
end
def create
@@referer_url
super
end
private
def get_pre_login_url(url)
@@referer_url = url
end
def after_sign_in_path_for(resource)
# @@referer_url
sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => 'http')
if @@referer_url == sign_in_url
super
else
stored_location_for(resource) || @@referer_url || root_path
end
end
end
You'll notice I'm setting a class variable ( @@variable_name
), which I'm not keen on, but this is what I came up with after 4 hours of trying various other ways of solving this. I'm also trying to be careful not to screw with Devise's controller too much and using super
and only including the actions I care about.
Next, in routes you can now point Devise's defaults to the Controller above. You don't need it exactly like below for the devise_for
, just the part referencing the controllers: { sessions: "sessions" }
MyPortfolio::Application.routes.draw do
devise_for :users, path_names: { sign_in: "login",
sign_out: "logout" },
controllers: { omniauth_callbacks: "omniauth_callbacks",
sessions: "sessions" }
resources :posts do
resources :comments
end
resources :projects do
resources :comments
end
resources :users
root :to => 'home#index'
get 'login' => 'devise/sessions#new'
get 'about_me' => 'about#index'
end
It might not be the DRYest solution around, but it was the only one that I was able to come up with to point the redirect back to the page of origin instead of root or an infinite loop.
您可以通过在控制器中定义after_sign_in_path_for
方法来完成此操作,您可以在其中自定义此重定向路径。
The following is more global solution but it can be used in your case. It uses attr_accessor. No extra params to after_sign_in_path_for
action and no class variable required.
class User < ActiveRecord::Base
attr_accessor :redirect_to
end
Then, with a dedicated sessions_controller file (override as recommended by Devise), copy-paste the original devise action and add the line resource.redirect_to = sign_in_params[:redirect_to]
before respond_with. Add the new redirect to the after_sign_in_path_for
action and add the :redirect_to
params to devise allowed signin params.
# app/controllers/devise/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
before_filter :configure_sign_in_params, only: [:create]
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
# set redirect_to
resource.redirect_to = sign_in_params[:redirect_to]
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
# set url to redirect_to url if present
def after_sign_in_path_for(resource_or_scope)
return resource_or_scope.redirect_to if resource_or_scope.redirect_to.present? && !resource_or_scope.respond_to?(:devise_scope)
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
end
# add redirect_to to devise signin allowed params
def configure_sign_in_params
devise_parameter_sanitizer.for(:sign_in) << :redirect_to
end
end
Finally, update your view to set a hidden param for the redirect_to
url
# app/views/users/sessions/new.html.haml
# from params in url
<% if (param_redirect_to = params[:redirect_to]).present?
<%= f.hidden_field :redirect_to, value: param_redirect_to %>
<% end %>
# or hardcoded if you have 2 sign-in forms
<%= f.hidden_field :redirect_to, value: 'your custom redirect url' %>
GET http://localhost:3000/login?redirect_to=www.test.com
will redirect your user to www.test.com after successful signing
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.