Last Updated: February 25, 2016
·
1.059K
· cdaloisio

dynamically remove default_scope from ActiveRecord models when using Devise

When you have a User model that has a default scope like:

default_scope ->{
   where(invitation_token: nil)
   .where.not(first_name: nil)
}

it can cause a lot of issues with Devise because all lookup methods on the resource don't remove the default_scope.

So, if you had someone who was invited and you wanted them to login to fill in their first name, they wouldn't be able to login to do this because their record would be filtered out by the defaultscope when setting currentuser.

By including this below, you can dynamically override all class methods in the Devise strategies that are responsible for lookup up the record and authenticating it through Warden.

require 'active_support/concern'

module DeviseOverrides
  extend ActiveSupport::Concern

  included do
    class << self
      # If you have other strategies, you could add/remove them from the array below
      [:authenticatable, :invitable, :database_authenticatable, :registerable, :confirmable,
      :recoverable, :rememberable, :validatable].each do |strategy|
        klass = "Devise::Models::#{strategy.to_s.camelize}::ClassMethods".constantize

        klass.instance_methods(false).each do |func|
          define_method(func) do |*args|
            unscoped { super(*args) }
          end
        end

      end
    end
  end

end

*This also makes it upgrade safe because if any class methods in Devise models get changed or added, it will automatically include them :) *

You could then include this into your User class, or any other class that you had a default_scope set.

class User < ActiveRecord::Base
  include DeviseOverrides
end