Skip to content

Instantly share code, notes, and snippets.

@mnishiguchi
Last active April 29, 2024 13:25
Show Gist options
  • Save mnishiguchi/8d4dbe468bd635595adb514432040793 to your computer and use it in GitHub Desktop.
Save mnishiguchi/8d4dbe468bd635595adb514432040793 to your computer and use it in GitHub Desktop.
Rails, Devise - Friendly forwarding after sign in or log in

Friendly forwarding

  • redirects users where they wanted to go after logging in.

module SessionsHelper
  # Redirects to stored location (or to the default).
  def redirect_back_or(default)
    redirect_to(session[:forwarding_url] || default)
    session.delete(:forwarding_url)
  end

  # Stores the URL trying to be accessed.
  def store_location
    session[:forwarding_url] = request.original_url if request.get?
  end
end

Devise/wiki

https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in

Log in

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  # Determine where to redirect user after successful login.
  # https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in
  def after_sign_in_path_for(resource)
    if request.referer == new_identity_session_url
      super
    else
      stored_location_for(resource) || request.referer || root_path
    end
  end
end

app/controllers/identities/sessions_controller.rb

class Identities::SessionsController < Devise::SessionsController
  # https://github.com/plataformatec/devise/issues/3461
  rescue_from ActionController::InvalidAuthenticityToken, with: :force_log_out

  # GET /resource/sign_in
  # https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in
  def new
    self.resource = resource_class.new(sign_in_params)
    store_location_for(resource, params[:redirect_to])
    super
  end
  
  # ...
end

Sign up

app/controllers/identities/registrations_controller.rb

class Identities::RegistrationsController < Devise::RegistrationsController
  def new
    build_resource({})
    store_location_for(resource, params[:redirect_to])

    yield resource if block_given?
    respond_with resource
  end

  # ...

  private

    def after_inactive_sign_up_path_for(resource)
      after_sign_in_path_for(resource) || super
    end
end

  • Devise-specific

Infrastructure

app/controllers/application_controller.rb

  • Store current path to an instance variable.
  • Customize after_sign_in_path_for so that we can specify a redirect_to path to Devise.
class ApplicationController < ActionController::Base
  # ...

  # By default, enable friendly forwarding if user is logged in
  before_action :set_redirect_path, unless: :user_signed_in?

  def set_redirect_path
    @redirect_path = request.path
  end

  # Override a Devise method
  def after_sign_in_path_for(resource)
    if params[:redirect_to].present?
      store_location_for(resource, params[:redirect_to])
    elsif request.referer == new_session_url
      super
    else
      stored_location_for(resource) || request.referer || root_path
    end
  end
end

app/helpers/application_helper.rb

  • We use this helper to pass a redirect_to path as a hash when we need to.
module ApplicationHelper
  def log_in_options
    @redirect_path ? {redirect_to: @redirect_path} : {}
  end
end

Views

app/views/layouts/application.html.erb

  • We can specify querystring as a hash to a url helper.
-# ...
= link_to "Log in", new_user_session_path( log_in_options )
-# ...

app/views/devise/sessions/new.html.erb

  • We pass the redirect_to path as a hidden field so that we can include it in the params.
-# ...

.actions
  = hidden_field_tag :redirect_to, params[:redirect_to]
  = f.submit "Log in"

-# ...

Request handler controller

app/controllers/episodes_controller.rb

  • By default, all the controllers can be friendly-forwarded after login.
  • We can disable the friendly forwarding for a given action.
class EpisodesController < ApplicationController
  # ...
  
  def index
    @redirect_path = false  # Disable friendly forwarding for this action.
    @episodes = Episode.all
  end
  
  # ...

Misc

request.referrer method

  • the previous URL
  • same as request.headers["HTTP_REFERER"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment