lib/devise/rails/routes.rb in devise-1.1.rc2 vs lib/devise/rails/routes.rb in devise-1.1.0

- old
+ new

@@ -13,35 +13,38 @@ class Mapper # Includes devise_for method for routes. This method is responsible to # 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 # # This method is going to look inside your User model and create the # 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: # # * :class_name => setup a different class to be looked up by devise, # if it cannot be correctly find by the route name. # @@ -60,100 +63,184 @@ # * :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :sign_up, # :password, :confirmation, :unlock. # # 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. + # * :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: # - # devise_for :users, :path_prefix => "/:locale" + # devise_for :users, :controllers => { :sessions => "users/sessions" } # - # 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: + # * :module => the namespace to find controlers. By default, devise will access devise/sessions, + # devise/registrations and so on. If you want to namespace all at once, use module: # - # class ApplicationController < ActionController::Base - # def self.default_url_options - # { :locale => I18n.locale } - # end - # end + # devise_for :users, :module => "users" # - # * :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: + # Notice that whenever you use namespace in the router DSL, it automatically sets the module. + # So the following setup: # - # devise_for :users, :controllers => { :sessions => "users/sessions" } + # namespace :publisher + # devise_for :account + # end # + # Will use publisher/sessions controller instead of devise/sessions controller. You can revert + # this by providing the :module option to devise_for. + # # * :skip => tell which controller you want to skip routes from being created: # # 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, it has one caveats. + # 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 + # def devise_for(*resources) options = resources.extract_options! + + if as = options.delete(:as) + ActiveSupport::Deprecation.warn ":as is deprecated, please use :path instead." + options[:path] ||= as + end + + if scope = options.delete(:scope) + ActiveSupport::Deprecation.warn ":scope is deprecated, please use :singular instead." + options[:singular] ||= scope + end + + options[:as] ||= @scope[:as] if @scope[:as].present? + options[:module] ||= @scope[:module] if @scope[:module].present? + options[:path_prefix] ||= @scope[:path] if @scope[:path].present? + options[:path_names] = (@scope[:path_names] || {}).merge(options[:path_names] || {}) + resources.map!(&:to_sym) resources.each do |resource| - mapping = Devise.add_model(resource, options) + mapping = Devise.add_mapping(resource, options) begin raise_no_devise_method_error!(mapping.class_name) unless mapping.to.respond_to?(:devise) + rescue NameError => e + raise unless mapping.class_name == resource.to_s.classify + warn "[WARNING] You provided devise_for #{resource.inspect} but there is " << + "no model #{mapping.class_name} defined in your application" + next rescue NoMethodError => e raise unless e.message.include?("undefined method `devise'") raise_no_devise_method_error!(mapping.class_name) end 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) + devise_scope mapping.name do + yield if block_given? + with_devise_exclusive_scope mapping.fullpath, mapping.name do + routes.each { |mod| send(:"devise_#{mod}", mapping, mapping.controllers) } + end 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) end constraints(constraint) do yield end end + # Sets the devise scope to be used in the controller. If you have custom routes, + # you are required to call this method (also aliased as :as) in order to specify + # to which controller it is targetted. + # + # as :user do + # get "sign_in", :to => "devise/sessions#new" + # end + # + # Notice you cannot have two scopes mapping to the same URL. And remember, if + # you try to access a devise controller without specifying a scope, it will + # raise ActionNotFound error. + def devise_scope(scope) + constraint = lambda do |request| + request.env["devise.mapping"] = Devise.mappings[scope] + true + end + + constraints(constraint) do + yield + end + end + alias :as :devise_scope + 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" + def devise_session(mapping, controllers) #:nodoc: + 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, :name_prefix => mapping.name do - resource :password, :only => [:new, :create, :edit, :update], :path => mapping.path_names[:password], :controller => controllers[:passwords] - end + def devise_password(mapping, controllers) #:nodoc: + 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, :name_prefix => mapping.name do - resource :confirmation, :only => [:new, :create, :show], :path => mapping.path_names[:confirmation], :controller => controllers[:confirmations] - end + def devise_confirmation(mapping, controllers) #:nodoc: + resource :confirmation, :only => [:new, :create, :show], + :path => mapping.path_names[:confirmation], :controller => controllers[:confirmations] end - def devise_unlock(mapping, controllers) - scope mapping.full_path, :name_prefix => mapping.name do - resource :unlock, :only => [:new, :create, :show], :path => mapping.path_names[:unlock], :controller => controllers[:unlocks] + def devise_unlock(mapping, controllers) #:nodoc: + if mapping.to.unlock_strategy_enabled?(:email) + resource :unlock, :only => [:new, :create, :show], + :path => mapping.path_names[:unlock], :controller => controllers[:unlocks] end end - def devise_registration(mapping, controllers) - scope mapping.full_path[1..-1], :name_prefix => 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 + def devise_registration(mapping, controllers) #:nodoc: + 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 - def raise_no_devise_method_error!(klass) + def with_devise_exclusive_scope(new_path, new_as) #:nodoc: + old_as, old_path, old_module = @scope[:as], @scope[:path], @scope[:module] + @scope[:as], @scope[:path], @scope[:module] = new_as, new_path, nil + yield + ensure + @scope[:as], @scope[:path], @scope[:module] = old_as, old_path, old_module + end + + def raise_no_devise_method_error!(klass) #:nodoc: raise "#{klass} does not respond to 'devise' method. This usually means you haven't " << "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 end