1
0
Fork 0
mirror of https://github.com/heartcombo/devise.git synced 2022-11-09 12:18:31 -05:00

Do not depend on silence_missing_strategies! anymore. This speeds up strategies matching because we don't need to check if the model duck types to the strategy and it doesn't trigger uneeded strategies.

This commit is contained in:
José Valim 2010-03-28 14:51:03 +02:00
parent 066c6e8771
commit 033db1ca7c
10 changed files with 81 additions and 51 deletions

View file

@ -27,7 +27,7 @@ module Devise
ALL = [] ALL = []
CONTROLLERS = {} CONTROLLERS = {}
ROUTES = [] ROUTES = []
STRATEGIES = [] STRATEGIES = ActiveSupport::OrderedHash.new
FLASH_MESSAGES = [:unauthenticated] FLASH_MESSAGES = [:unauthenticated]
# True values used to check params # True values used to check params
@ -122,49 +122,73 @@ module Devise
mattr_accessor :token_authentication_key mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token @@token_authentication_key = :auth_token
# The realm used in Http Basic Authentication # The realm used in Http Basic Authentication.
mattr_accessor :http_authentication_realm mattr_accessor :http_authentication_realm
@@http_authentication_realm = "Application" @@http_authentication_realm = "Application"
# Private methods to interface with Warden.
mattr_reader :warden_config
@@warden_config = nil
@@warden_config_block = nil
# Default way to setup Devise. Run rails generate devise_install to create # Default way to setup Devise. Run rails generate devise_install to create
# a fresh initializer with all configuration values. # a fresh initializer with all configuration values.
def self.setup def self.setup
yield self yield self
end end
# Register a model in Devise. You can call this manually if you don't want
# to use devise routes. Check devise_for in routes to know which options
# are available.
def self.register(resource, options)
mapping = Devise::Mapping.new(resource, options)
self.mappings[mapping.name] = mapping
self.default_scope ||= mapping.name
warden_config.default_scope ||= mapping.name
warden_config.scope_defaults mapping.name, :strategies => mapping.strategies
mapping
end
# Make Devise aware of an 3rd party Devise-module. For convenience. # Make Devise aware of an 3rd party Devise-module. For convenience.
# #
# == Options: # == Options:
# #
# +strategy+ - Boolean value representing if this module got a custom *strategy*.
# Default is +false+. Note: Devise will auto-detect this in such case if this is true.
# +model+ - String representing the load path to a custom *model* for this module (to autoload.) # +model+ - String representing the load path to a custom *model* for this module (to autoload.)
# Default is +nil+ (i.e. +false+).
# +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module. # +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
# Default is +nil+ (i.e. +false+). # +route+ - Symbol representing the named *route* helper for this module.
# +route+ - Symbol representing the named *router* helper for this module.
# Default is +nil+ (i.e. +false+).
# +flash+ - Symbol representing the *flash messages* used by this helper. # +flash+ - Symbol representing the *flash messages* used by this helper.
# Default is +nil+ (i.e. +false+). # +strategy+ - Symbol representing if this module got a custom *strategy*.
#
# All values, except :model, accept also a boolean and will have the same name as the given module
# name.
# #
# == Examples: # == Examples:
# #
# Devise.add_module(:party_module) # Devise.add_module(:party_module)
# Devise.add_module(:party_module, :strategy => true, :controller => :sessions) # Devise.add_module(:party_module, :strategy => true, :controller => :sessions)
# Devise.add_module(:party_module, :autoload => 'party_module/model') # Devise.add_module(:party_module, :model => 'party_module/model')
# #
def self.add_module(module_name, options = {}) def self.add_module(module_name, options = {})
ALL << module_name ALL << module_name
options.assert_valid_keys(:strategy, :model, :controller, :route, :flash) options.assert_valid_keys(:strategy, :model, :controller, :route, :flash, :passive_strategy)
{ :strategy => STRATEGIES, :flash => FLASH_MESSAGES, :route => ROUTES }.each do |key, value| config = {
:strategy => STRATEGIES,
:flash => FLASH_MESSAGES,
:route => ROUTES,
:controller => CONTROLLERS
}
config.each do |key, value|
next unless options[key] next unless options[key]
name = (options[key] == true ? module_name : options[key]) name = (options[key] == true ? module_name : options[key])
value.unshift(name) unless value.include?(name)
end
if options[:controller] if value.is_a?(Hash)
Devise::CONTROLLERS[module_name] = options[:controller].to_sym value[module_name] = name
else
value << name unless value.include?(name)
end
end end
if options[:model] if options[:model]
@ -172,7 +196,7 @@ module Devise
Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, model_path) Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, model_path)
end end
Devise::Mapping.register module_name Devise::Mapping.add_module module_name
end end
# Sets warden configuration using a block that will be invoked on warden # Sets warden configuration using a block that will be invoked on warden
@ -187,19 +211,17 @@ module Devise
# end # end
# end # end
def self.warden(&block) def self.warden(&block)
@warden_config = block @@warden_config_block = block
end end
# A method used internally to setup warden manager from the Rails initialize # A method used internally to setup warden manager from the Rails initialize
# block. # block.
def self.configure_warden(config) #:nodoc: def self.configure_warden(config) #:nodoc:
config.default_strategies *Devise::STRATEGIES
config.failure_app = Devise::FailureApp config.failure_app = Devise::FailureApp
config.silence_missing_strategies!
config.default_scope = Devise.default_scope config.default_scope = Devise.default_scope
# If the user provided a warden hook, call it now. @@warden_config = config
@warden_config.try :call, config @@warden_config_block.try :call, config
end end
# Generate a friendly string randomically to be used as token. # Generate a friendly string randomically to be used as token.

View file

@ -77,6 +77,10 @@ module Devise
klass klass
end end
def strategies
@strategies ||= STRATEGIES.values_at(*self.modules).compact.reverse
end
# Keep a list of allowed controllers for this mapping. It's useful to ensure # Keep a list of allowed controllers for this mapping. It's useful to ensure
# that an Admin cannot access the registrations controller unless it has # that an Admin cannot access the registrations controller unless it has
# :registerable in the model. # :registerable in the model.
@ -104,7 +108,7 @@ module Devise
# self.modules.include?(:confirmable) # self.modules.include?(:confirmable)
# end # end
# #
def self.register(m) def self.add_module(m)
class_eval <<-METHOD, __FILE__, __LINE__ + 1 class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{m}? def #{m}?
self.modules.include?(:#{m}) self.modules.include?(:#{m})

View file

@ -92,17 +92,14 @@ module ActionDispatch::Routing
resources.map!(&:to_sym) resources.map!(&:to_sym)
resources.each do |resource| resources.each do |resource|
mapping = Devise::Mapping.new(resource, options) mapping = Devise.register(resource, options)
unless mapping.to.respond_to?(:devise) unless mapping.to.respond_to?(:devise)
raise "#{mapping.to.name} does not respond to 'devise' method. This usually means you haven't " << raise "#{mapping.to.name} does not respond to 'devise' method. This usually means you haven't " <<
"loaded your ORM file or it's being loaded to late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " << "loaded your ORM file or it's being loaded too late. To fix it, be sure to require 'devise/orm/YOUR_ORM' " <<
"inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'" "inside 'config/initializers/devise.rb' or before your application definition in 'config/application.rb'"
end end
Devise.default_scope ||= mapping.name
Devise.mappings[mapping.name] = mapping
routes_modules = mapping.modules - Array(options.delete(:skip)) routes_modules = mapping.modules - Array(options.delete(:skip))
routes_modules.each do |mod| routes_modules.each do |mod|
send(mod, mapping, mapping.controllers) if self.respond_to?(mod, true) send(mod, mapping, mapping.controllers) if self.respond_to?(mod, true)

View file

@ -6,7 +6,7 @@ module Devise
# Redirects to sign_in page if it's not authenticated # Redirects to sign_in page if it's not authenticated
class Authenticatable < Base class Authenticatable < Base
def valid? def valid?
valid_controller? && valid_params? && mapping.to.respond_to?(:authenticate) valid_controller? && valid_params?
end end
# Authenticate a user based on email and password params, returning to warden # Authenticate a user based on email and password params, returning to warden

View file

@ -5,7 +5,7 @@ module Devise
# Sign in an user using HTTP authentication. # Sign in an user using HTTP authentication.
class HttpAuthenticatable < Base class HttpAuthenticatable < Base
def valid? def valid?
request.authorization && mapping.to.respond_to?(:authenticate_with_http) request.authorization
end end
def authenticate! def authenticate!

View file

@ -10,7 +10,7 @@ module Devise
# A valid strategy for rememberable needs a remember token in the cookies. # A valid strategy for rememberable needs a remember token in the cookies.
def valid? def valid?
remember_me_cookie.present? && mapping.to.respond_to?(:serialize_from_cookie) remember_me_cookie.present?
end end
# To authenticate a user we deserialize the cookie and attempt finding # To authenticate a user we deserialize the cookie and attempt finding

View file

@ -6,7 +6,7 @@ module Devise
# Redirects to sign_in page if it's not authenticated. # Redirects to sign_in page if it's not authenticated.
class TokenAuthenticatable < Base class TokenAuthenticatable < Base
def valid? def valid?
mapping.to.respond_to?(:authenticate_with_token) && authentication_token(scope).present? authentication_token(scope).present?
end end
# Authenticate a user based on authenticatable token params, returning to warden # Authenticate a user based on authenticatable token params, returning to warden

View file

@ -15,7 +15,7 @@ module Devise
def initialize(controller) def initialize(controller)
@controller = controller @controller = controller
manager = Warden::Manager.new(nil) do |config| manager = Warden::Manager.new(nil) do |config|
Devise.configure_warden(config) config.merge! Devise.warden_config
end end
super(controller.request.env, manager) super(controller.request.env, manager)
end end

View file

@ -1,8 +1,11 @@
require 'test_helper' require 'test_helper'
module Devise module Devise
def self.clean_warden_config! def self.yield_and_restore
@warden_config = nil c, b = @@warden_config, @@warden_config_block
yield
ensure
@@warden_config, @@warden_config_block = c, b
end end
end end
@ -21,17 +24,17 @@ class DeviseTest < ActiveSupport::TestCase
end end
test 'warden manager configuration' do test 'warden manager configuration' do
Devise.yield_and_restore do
config = Warden::Config.new config = Warden::Config.new
Devise.configure_warden(config) Devise.configure_warden(config)
assert_equal Devise::FailureApp, config.failure_app assert_equal Devise::FailureApp, config.failure_app
assert_equal [:rememberable, :token_authenticatable, :http_authenticatable, :authenticatable], config.default_strategies
assert_equal :user, config.default_scope assert_equal :user, config.default_scope
assert config.silence_missing_strategies? end
end end
test 'warden manager user configuration through a block' do test 'warden manager user configuration through a block' do
begin Devise.yield_and_restore do
@executed = false @executed = false
Devise.warden do |config| Devise.warden do |config|
@executed = true @executed = true
@ -40,8 +43,6 @@ class DeviseTest < ActiveSupport::TestCase
Devise.configure_warden(Warden::Config.new) Devise.configure_warden(Warden::Config.new)
assert @executed assert @executed
ensure
Devise.clean_warden_config!
end end
end end
@ -52,8 +53,8 @@ class DeviseTest < ActiveSupport::TestCase
assert_not defined?(Devise::Models::Coconut) assert_not defined?(Devise::Models::Coconut)
Devise::ALL.delete(:coconut) Devise::ALL.delete(:coconut)
assert_nothing_raised(Exception) { Devise.add_module(:banana, :strategy => true) } assert_nothing_raised(Exception) { Devise.add_module(:banana, :strategy => :fruits) }
assert_equal 1, Devise::STRATEGIES.select { |v| v == :banana }.size assert_equal :fruits, Devise::STRATEGIES[:banana]
Devise::ALL.delete(:banana) Devise::ALL.delete(:banana)
Devise::STRATEGIES.delete(:banana) Devise::STRATEGIES.delete(:banana)

View file

@ -13,7 +13,7 @@ class MappingTest < ActiveSupport::TestCase
assert_equal :admin_area, Devise.mappings[:admin].as assert_equal :admin_area, Devise.mappings[:admin].as
end end
test 'allow custom scope to be given' do test 'allows custom scope to be given' do
assert_equal :accounts, Devise.mappings[:manager].as assert_equal :accounts, Devise.mappings[:manager].as
end end
@ -29,6 +29,12 @@ class MappingTest < ActiveSupport::TestCase
assert_not allowed.include?("devise/unlocks") assert_not allowed.include?("devise/unlocks")
end end
test 'has strategies depending on the model declaration' do
assert_equal [:rememberable, :token_authenticatable,
:http_authenticatable, :authenticatable], Devise.mappings[:user].strategies
assert_equal [:authenticatable], Devise.mappings[:admin].strategies
end
test 'find mapping by path' do test 'find mapping by path' do
assert_nil Devise::Mapping.find_by_path("/foo/bar") assert_nil Devise::Mapping.find_by_path("/foo/bar")
assert_equal Devise.mappings[:user], Devise::Mapping.find_by_path("/users/session") assert_equal Devise.mappings[:user], Devise::Mapping.find_by_path("/users/session")