Jerome
Jerome

Reputation: 6217

Ruby wildcard on path

The following ruby code to store a previous URL is meant to exclude a certain series where the resulting action might send the user in an endless loop.

  def current_user_url   # store last url 
    if (request.fullpath != "/users/sign_in?locale=*" &&
        request.fullpath != "/users/sign_up?locale=*" &&
        request.fullpath != "/users/password?locale=*" &&
        request.fullpath != "/users/sign_out?locale=*" &&
        request.fullpath != "/users?locale=*" &&
        !request.xhr?) # don't store ajax calls
      session[:previous_url] = request.fullpath 
    end
  end

when handling self-referential actions

def after_sign_in_path_for(resource)
  session[:previous_url] || session[:confirm_url]
end

The wildcard character is not working as desired, as the session variable is storing, for example, /users/sign_in?locale=en notwithstanding the use of the wildcard. note: without the use of ?locale=en the function does work as expected.

How can this code become locale agnostic?

Update with note on solution

In case anyone drops by and is flustered by the second apporach of a wiki for the devise gem, you're not alone. I wasn't too thrilled instinctively with an after filter. Digging into Devise's store location method is an option, though not as straightforward as Max's solution below.

That does need a slight tweak though (and [ahem, yes] the question did not mention devise) where routes need to invoke devise_for and the controller needs to inherit from devise

 devise_for :users, :controllers => { registrations: 'registrations', sessions: 'sessions' } 

class SessionsController < Devise::SessionsController
  skip_before_action :store_location 
end

This feels cleaner to me come maintenance time...

Upvotes: 0

Views: 696

Answers (2)

max
max

Reputation: 102250

Instead of request.full_path you can use request.path which does not include the query string.

But a better solution altogether is just skipping the callback on the effected controllers / actions as this distributes the responsibilities correctly.

class ApplicationController < ActionController::Base
  before_action :store_location
  def store_location
    session[:previous_url] = request.fullpath 
  end 
end

class SessionsController < ApplicationController
  skip_before_action :store_location
end

class UsersController < ApplicationController
  skip_before_action :store_location, only: :index
end

Upvotes: 1

user229044
user229044

Reputation: 239501

Wildcards don't work in string comparisons, which are just straight character-by-character equality checks.

You need to use a regular expression, and check for a match, or use String#[]:

if (!request.fullpath[%r{\A/users/sign_in\?locale=.*\z}] &&
  ...

Upvotes: 0

Related Questions