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

Allow devise_for to be scoped with the scope method. This commit requires latest commits in Rails master.

This commit is contained in:
José Valim 2010-06-30 12:41:44 +02:00
parent 78e7642bd2
commit 2103a673f0
5 changed files with 96 additions and 62 deletions

View file

@ -149,6 +149,7 @@ module Devise
mattr_accessor :token_authentication_key
@@token_authentication_key = :auth_token
# Which formats should be treated as navigational.
mattr_accessor :navigational_formats
@@navigational_formats = [:html]
@ -157,9 +158,14 @@ module Devise
@@warden_config = nil
@@warden_config_block = nil
# When set to true, signing out an user signs out all other scopes.
mattr_accessor :sign_out_all_scopes
@@sign_out_all_scopes = false
# When set to true, optional segments in Devise no longer raises an error.
mattr_accessor :ignore_optional_segments
@@ignore_otional_segments = false
# Default way to setup Devise. Run rails generate devise_install to create
# a fresh initializer with all configuration values.
def self.setup

View file

@ -70,6 +70,12 @@ module Devise
@path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
if @path_prefix =~ /\(.*\)/ && Devise.ignore_optional_segments != true
raise ScriptError, "It seems that you are scoping devise_for with an optional segment #{@path_prefix.inspect} " <<
"which Devise does not support. Please remove the optional segment or alternatively, if you are *sure* of " <<
"what you are doing, you can set config.ignore_optional_segments = true in your devise initializer."
end
@controllers = Hash.new { |h,k| h[k] = "devise/#{k}" }
@controllers.merge!(options.delete(:controllers) || {})
@ -111,11 +117,6 @@ module Devise
self.path_prefix.count("/")
end
# Returns the raw path using path_prefix and as.
def full_path
path_prefix + path.to_s
end
def authenticatable?
@authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
end

View file

@ -15,9 +15,10 @@ module ActionDispatch::Routing
# generate all needed routes for devise, based on what modules you have
# defined in your model.
#
# Examples: Let's say you have an User model configured to use
# authenticatable, confirmable and recoverable modules. After creating this
# inside your routes:
# ==== Examples
#
# Let's say you have an User model configured to use authenticatable,
# confirmable and recoverable modules. After creating this inside your routes:
#
# devise_for :users
#
@ -25,20 +26,22 @@ module ActionDispatch::Routing
# needed routes:
#
# # Session routes for Authenticatable (default)
# new_user_session GET /users/sign_in {:controller=>"sessions", :action=>"new"}
# user_session POST /users/sign_in {:controller=>"sessions", :action=>"create"}
# destroy_user_session GET /users/sign_out {:controller=>"sessions", :action=>"destroy"}
# new_user_session GET /users/sign_in {:controller=>"devise/sessions", :action=>"new"}
# user_session POST /users/sign_in {:controller=>"devise/sessions", :action=>"create"}
# destroy_user_session GET /users/sign_out {:controller=>"devise/sessions", :action=>"destroy"}
#
# # Password routes for Recoverable, if User model has :recoverable configured
# new_user_password GET /users/password/new(.:format) {:controller=>"passwords", :action=>"new"}
# edit_user_password GET /users/password/edit(.:format) {:controller=>"passwords", :action=>"edit"}
# user_password PUT /users/password(.:format) {:controller=>"passwords", :action=>"update"}
# POST /users/password(.:format) {:controller=>"passwords", :action=>"create"}
# new_user_password GET /users/password/new(.:format) {:controller=>"devise/passwords", :action=>"new"}
# edit_user_password GET /users/password/edit(.:format) {:controller=>"devise/passwords", :action=>"edit"}
# user_password PUT /users/password(.:format) {:controller=>"devise/passwords", :action=>"update"}
# POST /users/password(.:format) {:controller=>"devise/passwords", :action=>"create"}
#
# # Confirmation routes for Confirmable, if User model has :confirmable configured
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"confirmations", :action=>"new"}
# user_confirmation GET /users/confirmation(.:format) {:controller=>"confirmations", :action=>"show"}
# POST /users/confirmation(.:format) {:controller=>"confirmations", :action=>"create"}
# new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"devise/confirmations", :action=>"new"}
# user_confirmation GET /users/confirmation(.:format) {:controller=>"devise/confirmations", :action=>"show"}
# POST /users/confirmation(.:format) {:controller=>"devise/confirmations", :action=>"create"}
#
# ==== Options
#
# You can configure your routes with some options:
#
@ -62,19 +65,6 @@ module ActionDispatch::Routing
#
# devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
#
# * :path_prefix => the path prefix to be used in all routes.
#
# devise_for :users, :path_prefix => "/:locale"
#
# If you are using a dynamic prefix, like :locale above, you need to configure default_url_options in your ApplicationController
# class level, so Devise can pick it:
#
# class ApplicationController < ActionController::Base
# def self.default_url_options
# { :locale => I18n.locale }
# end
# end
#
# * :controllers => the controller which should be used. All routes by default points to Devise controllers.
# However, if you want them to point to custom controller, you should do:
#
@ -84,8 +74,46 @@ module ActionDispatch::Routing
#
# devise_for :users, :skip => :sessions
#
# ==== Scoping
#
# Following Rails 3 routes DSL, you can nest devise_for calls inside a scope:
#
# scope "/my" do
# devise_for :users
# end
#
# However, since Devise uses the request path to retrieve the current user, this has a few caveats.
# First, if you are using a dynamic segment, as below:
#
# scope ":locale" do
# devise_for :users
# end
#
# You are required to configure default_url_options in your ApplicationController class level, so
# Devise can pick it:
#
# class ApplicationController < ActionController::Base
# def self.default_url_options
# { :locale => I18n.locale }
# end
# end
#
# Finally, Devise does not (and cannot) support optional segments, either static or dynamic. That
# said, the following does not work:
#
# scope "(/:locale)" do
# devise_for :users
# end
#
def devise_for(*resources)
options = resources.extract_options!
if options.key?(:path_prefix)
ActiveSupport::Deprecation.warn "Giving :path_prefix to devise_for is deprecated and has no effect. " <<
"Please use scope from the new router DSL instead."
end
options[:path_prefix] = @scope[:path]
resources.map!(&:to_sym)
resources.each do |resource|
@ -106,12 +134,18 @@ module ActionDispatch::Routing
routes = mapping.routes
routes -= Array(options.delete(:skip)).map { |s| s.to_s.singularize.to_sym }
routes.each do |mod|
send(:"devise_#{mod}", mapping, mapping.controllers)
scope mapping.path.to_s, :as => mapping.name do
routes.each { |mod| send(:"devise_#{mod}", mapping, mapping.controllers) }
end
end
end
# Allow you to add authentication request from the router:
#
# authenticate(:user) do
# resources :post
# end
#
def authenticate(scope)
constraint = lambda do |request|
request.env["warden"].authenticate!(:scope => scope)
@ -125,37 +159,32 @@ module ActionDispatch::Routing
protected
def devise_session(mapping, controllers)
scope mapping.full_path do
get mapping.path_names[:sign_in], :to => "#{controllers[:sessions]}#new", :as => :"new_#{mapping.name}_session"
post mapping.path_names[:sign_in], :to => "#{controllers[:sessions]}#create", :as => :"#{mapping.name}_session"
get mapping.path_names[:sign_out], :to => "#{controllers[:sessions]}#destroy", :as => :"destroy_#{mapping.name}_session"
scope :controller => controllers[:sessions], :as => :session do
get :new, :path => mapping.path_names[:sign_in]
post :create, :path => mapping.path_names[:sign_in], :as => ""
get :destroy, :path => mapping.path_names[:sign_out]
end
end
def devise_password(mapping, controllers)
scope mapping.full_path, :as => mapping.name do
resource :password, :only => [:new, :create, :edit, :update], :path => mapping.path_names[:password], :controller => controllers[:passwords]
end
resource :password, :only => [:new, :create, :edit, :update],
:path => mapping.path_names[:password], :controller => controllers[:passwords]
end
def devise_confirmation(mapping, controllers)
scope mapping.full_path, :as => mapping.name do
resource :confirmation, :only => [:new, :create, :show], :path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
end
resource :confirmation, :only => [:new, :create, :show],
:path => mapping.path_names[:confirmation], :controller => controllers[:confirmations]
end
def devise_unlock(mapping, controllers)
scope mapping.full_path, :as => mapping.name do
resource :unlock, :only => [:new, :create, :show], :path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
end
resource :unlock, :only => [:new, :create, :show],
:path => mapping.path_names[:unlock], :controller => controllers[:unlocks]
end
def devise_registration(mapping, controllers)
scope mapping.full_path[1..-1], :as => mapping.name do
resource :registration, :only => [:new, :create, :edit, :update, :destroy], :path => mapping.path_names[:registration],
:path_names => { :new => mapping.path_names[:sign_up] }, :controller => controllers[:registrations]
end
end
def raise_no_devise_method_error!(klass)
raise "#{klass} does not respond to 'devise' method. This usually means you haven't " <<

View file

@ -97,11 +97,6 @@ class MappingTest < ActiveSupport::TestCase
assert_equal 2, Devise.mappings[:manager].segment_position
end
test 'path is returned with path prefix and as' do
assert_equal '/users', Devise.mappings[:user].full_path
assert_equal '/:locale/accounts', Devise.mappings[:manager].full_path
end
test 'magic predicates' do
mapping = Devise.mappings[:user]
assert mapping.authenticatable?

View file

@ -8,13 +8,16 @@ Rails::Application.routes.draw do
devise_for :users
devise_for :admin, :path => "admin_area", :controllers => { :sessions => "sessions" }, :skip => :passwords
devise_for :accounts, :singular => "manager", :path_prefix => ":locale", :class_name => "User",
scope ":locale" do
devise_for :accounts, :singular => "manager", :class_name => "User",
:path_names => {
:sign_in => "login", :sign_out => "logout",
:password => "secret", :confirmation => "verification",
:unlock => "unblock", :sign_up => "register",
:registration => "management"
}
end
match "/admin_area/home", :to => "admins#index", :as => :admin_root
match "/sign_in", :to => "devise/sessions#new"