简体   繁体   中英

Devise how to redirect to different page (based on some parameter) after sign in?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM