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 = []
CONTROLLERS = {}
ROUTES = []
STRATEGIES = []
STRATEGIES = ActiveSupport::OrderedHash.new
FLASH_MESSAGES = [:unauthenticated]
# True values used to check params
@ -122,49 +122,73 @@ module Devise
mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token
# The realm used in Http Basic Authentication
# The realm used in Http Basic Authentication.
mattr_accessor :http_authentication_realm
@@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
# a fresh initializer with all configuration values.
def self.setup
yield self
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.
#
# == 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.)
# Default is +nil+ (i.e. +false+).
# +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 *router* helper for this module.
# Default is +nil+ (i.e. +false+).
# +flash+ - Symbol representing the *flash messages* used by this helper.
# Default is +nil+ (i.e. +false+).
# +model+ - String representing the load path to a custom *model* for this module (to autoload.)
# +controller+ - Symbol representing the name of an exisiting or custom *controller* for this module.
# +route+ - Symbol representing the named *route* helper for this module.
# +flash+ - Symbol representing the *flash messages* used by this helper.
# +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:
#
# Devise.add_module(:party_module)
# 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 = {})
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]
name = (options[key] == true ? module_name : options[key])
value.unshift(name) unless value.include?(name)
end
if options[:controller]
Devise::CONTROLLERS[module_name] = options[:controller].to_sym
if value.is_a?(Hash)
value[module_name] = name
else
value << name unless value.include?(name)
end
end
if options[:model]
@ -172,7 +196,7 @@ module Devise
Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, model_path)
end
Devise::Mapping.register module_name
Devise::Mapping.add_module module_name
end
# Sets warden configuration using a block that will be invoked on warden
@ -187,19 +211,17 @@ module Devise
# end
# end
def self.warden(&block)
@warden_config = block
@@warden_config_block = block
end
# A method used internally to setup warden manager from the Rails initialize
# block.
def self.configure_warden(config) #:nodoc:
config.default_strategies *Devise::STRATEGIES
config.failure_app = Devise::FailureApp
config.silence_missing_strategies!
config.failure_app = Devise::FailureApp
config.default_scope = Devise.default_scope
# If the user provided a warden hook, call it now.
@warden_config.try :call, config
@@warden_config = config
@@warden_config_block.try :call, config
end
# Generate a friendly string randomically to be used as token.

View File

@ -77,6 +77,10 @@ module Devise
klass
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
# that an Admin cannot access the registrations controller unless it has
# :registerable in the model.
@ -104,7 +108,7 @@ module Devise
# self.modules.include?(:confirmable)
# end
#
def self.register(m)
def self.add_module(m)
class_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{m}?
self.modules.include?(:#{m})

View File

@ -92,17 +92,14 @@ module ActionDispatch::Routing
resources.map!(&:to_sym)
resources.each do |resource|
mapping = Devise::Mapping.new(resource, options)
mapping = Devise.register(resource, options)
unless mapping.to.respond_to?(:devise)
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'"
end
Devise.default_scope ||= mapping.name
Devise.mappings[mapping.name] = mapping
routes_modules = mapping.modules - Array(options.delete(:skip))
routes_modules.each do |mod|
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
class Authenticatable < Base
def valid?
valid_controller? && valid_params? && mapping.to.respond_to?(:authenticate)
valid_controller? && valid_params?
end
# 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.
class HttpAuthenticatable < Base
def valid?
request.authorization && mapping.to.respond_to?(:authenticate_with_http)
request.authorization
end
def authenticate!

View File

@ -10,7 +10,7 @@ module Devise
# A valid strategy for rememberable needs a remember token in the cookies.
def valid?
remember_me_cookie.present? && mapping.to.respond_to?(:serialize_from_cookie)
remember_me_cookie.present?
end
# 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.
class TokenAuthenticatable < Base
def valid?
mapping.to.respond_to?(:authenticate_with_token) && authentication_token(scope).present?
authentication_token(scope).present?
end
# Authenticate a user based on authenticatable token params, returning to warden

View File

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

View File

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

View File

@ -13,7 +13,7 @@ class MappingTest < ActiveSupport::TestCase
assert_equal :admin_area, Devise.mappings[:admin].as
end
test 'allow custom scope to be given' do
test 'allows custom scope to be given' do
assert_equal :accounts, Devise.mappings[:manager].as
end
@ -29,6 +29,12 @@ class MappingTest < ActiveSupport::TestCase
assert_not allowed.include?("devise/unlocks")
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
assert_nil Devise::Mapping.find_by_path("/foo/bar")
assert_equal Devise.mappings[:user], Devise::Mapping.find_by_path("/users/session")