diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/routing/mapper.rb')
-rw-r--r-- | actionpack/lib/action_dispatch/routing/mapper.rb | 168 |
1 files changed, 84 insertions, 84 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0b4ba8c9f5..430f6fc5a3 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -13,6 +13,8 @@ module ActionDispatch end end + attr_reader :app + def initialize(app, constraints, request) @app, @constraints, @request = app, constraints, request end @@ -63,6 +65,16 @@ module ActionDispatch end end + if path.match(':controller') + raise ArgumentError, ":controller segment is not allowed within a namespace block" if @scope[:module] + + # Add a default constraint for :controller path segments that matches namespaced + # controllers with default routes like :controller/:action/:id(.:format), e.g: + # GET /admin/products/show/1 + # => { :controller => 'admin/products', :action => 'show', :id => '1' } + options.reverse_merge!(:controller => /.+?/) + end + path = normalize_path(path) path_without_format = path.sub(/\(\.:format\)$/, '') @@ -133,8 +145,11 @@ module ActionDispatch defaults[:controller] ||= default_controller defaults[:action] ||= default_action - defaults.delete(:controller) if defaults[:controller].blank? - defaults.delete(:action) if defaults[:action].blank? + defaults.delete(:controller) if defaults[:controller].blank? || defaults[:controller].is_a?(Regexp) + defaults.delete(:action) if defaults[:action].blank? || defaults[:action].is_a?(Regexp) + + defaults[:controller] = defaults[:controller].to_s if defaults.key?(:controller) + defaults[:action] = defaults[:action].to_s if defaults.key?(:action) if defaults[:controller].blank? && segment_keys.exclude?("controller") raise ArgumentError, "missing :controller" @@ -183,15 +198,15 @@ module ActionDispatch def default_controller if @options[:controller] - @options[:controller].to_s + @options[:controller] elsif @scope[:controller] - @scope[:controller].to_s + @scope[:controller] end end def default_action if @options[:action] - @options[:action].to_s + @options[:action] end end end @@ -431,12 +446,16 @@ module ActionDispatch end def merge_options_scope(parent, child) - (parent || {}).merge(child) + (parent || {}).except(*override_keys(child)).merge(child) end def merge_shallow_scope(parent, child) child ? true : false end + + def override_keys(child) + child.key?(:only) || child.key?(:except) ? [:only, :except] : [] + end end module Resources @@ -444,7 +463,7 @@ module ActionDispatch # a path appended since they fit properly in their scope level. VALID_ON_OPTIONS = [:new, :collection, :member] CANONICAL_ACTIONS = [:index, :create, :new, :show, :update, :destroy] - MERGE_FROM_SCOPE_OPTIONS = [:shallow, :constraints] + RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except] class Resource #:nodoc: DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit] @@ -464,9 +483,9 @@ module ActionDispatch end def actions - if only = options[:only] + if only = @options[:only] Array(only).map(&:to_sym) - elsif except = options[:except] + elsif except = @options[:except] default_actions - Array(except).map(&:to_sym) else default_actions @@ -489,68 +508,31 @@ module ActionDispatch singular end - alias_method :nested_name, :member_name - # Checks for uncountable plurals, and appends "_index" if they're. def collection_name singular == plural ? "#{plural}_index" : plural end - def shallow? - options[:shallow] ? true : false - end - - def constraints - options[:constraints] || {} - end - - def id_constraint? - options[:id] && options[:id].is_a?(Regexp) || constraints[:id] && constraints[:id].is_a?(Regexp) - end - - def id_constraint - options[:id] || constraints[:id] - end - - def collection_options - (options || {}).dup.tap do |opts| - opts.delete(:id) - opts[:constraints] = options[:constraints].dup if options[:constraints] - opts[:constraints].delete(:id) if options[:constraints].is_a?(Hash) - end - end - - def nested_path - "#{path}/:#{singular}_id" - end - - def nested_options - {}.tap do |opts| - opts[:as] = member_name - opts["#{singular}_id".to_sym] = id_constraint if id_constraint? - opts[:options] = { :shallow => shallow? } unless options[:shallow].nil? - end - end - def resource_scope - [{ :controller => controller }] + { :controller => controller } end def collection_scope - [path, collection_options] + path end def member_scope - ["#{path}/:id", options] + "#{path}/:id" end def new_scope(new_path) - ["#{path}/#{new_path}"] + "#{path}/#{new_path}" end def nested_scope - [nested_path, nested_options] + "#{path}/:#{singular}_id" end + end class SingletonResource < Resource #:nodoc: @@ -559,7 +541,7 @@ module ActionDispatch def initialize(entities, options) @name = entities.to_s @path = options.delete(:path) || @name - @controller = (options.delete(:controller) || @name.to_s.pluralize).to_s + @controller = (options.delete(:controller) || plural).to_s @as = options.delete(:as) @options = options end @@ -569,24 +551,10 @@ module ActionDispatch end alias :collection_name :member_name - def nested_path - path - end - - def nested_options - {}.tap do |opts| - opts[:as] = member_name - opts[:options] = { :shallow => shallow? } unless @options[:shallow].nil? - end - end - - def shallow? - false - end - def member_scope - [path, options] + path end + alias :nested_scope :member_scope end def initialize(*args) #:nodoc: @@ -693,18 +661,18 @@ module ActionDispatch end with_scope_level(:nested) do - if parent_resource.shallow? + if shallow? with_exclusive_scope do if @scope[:shallow_path].blank? - scope(*parent_resource.nested_scope) { yield } + scope(parent_resource.nested_scope, nested_options) { yield } else scope(@scope[:shallow_path], :as => @scope[:shallow_prefix]) do - scope(*parent_resource.nested_scope) { yield } + scope(parent_resource.nested_scope, nested_options) { yield } end end end else - scope(*parent_resource.nested_scope) { yield } + scope(parent_resource.nested_scope, nested_options) { yield } end end end @@ -723,6 +691,10 @@ module ActionDispatch end end + def shallow? + parent_resource.instance_of?(Resource) && @scope[:shallow] + end + def match(*args) options = args.extract_options!.dup options[:anchor] = true unless options.key?(:anchor) @@ -800,16 +772,17 @@ module ActionDispatch return true end - if path_names = options.delete(:path_names) - scope(:path_names => path_names) do + scope_options = options.slice!(*RESOURCE_OPTIONS) + unless scope_options.empty? + scope(scope_options) do send(method, resources.pop, options, &block) end return true end - scope_options = @scope.slice(*MERGE_FROM_SCOPE_OPTIONS).delete_if{ |k,v| v.blank? } - options.reverse_merge!(scope_options) unless scope_options.empty? - options.reverse_merge!(@scope[:options]) unless @scope[:options].blank? + unless action_options?(options) + options.merge!(scope_action_options) if scope_action_options? + end if resource_scope? nested do @@ -821,6 +794,18 @@ module ActionDispatch false end + def action_options?(options) + options[:only] || options[:except] + end + + def scope_action_options? + @scope[:options].is_a?(Hash) && (@scope[:options][:only] || @scope[:options][:except]) + end + + def scope_action_options + @scope[:options].slice(:only, :except) + end + def resource_scope? [:resource, :resources].include?(@scope[:scope_level]) end @@ -853,7 +838,7 @@ module ActionDispatch def resource_scope(resource) with_scope_level(resource.is_a?(SingletonResource) ? :resource : :resources, resource) do - scope(*parent_resource.resource_scope) do + scope(parent_resource.resource_scope) do yield end end @@ -861,7 +846,7 @@ module ActionDispatch def new_scope with_scope_level(:new) do - scope(*parent_resource.new_scope(action_path(:new))) do + scope(parent_resource.new_scope(action_path(:new))) do yield end end @@ -869,7 +854,7 @@ module ActionDispatch def collection_scope with_scope_level(:collection) do - scope(*parent_resource.collection_scope) do + scope(parent_resource.collection_scope) do yield end end @@ -877,18 +862,33 @@ module ActionDispatch def member_scope with_scope_level(:member) do - scope(*parent_resource.member_scope) do + scope(parent_resource.member_scope) do yield end end end + def nested_options + {}.tap do |options| + options[:as] = parent_resource.member_name + options[:constraints] = { "#{parent_resource.singular}_id".to_sym => id_constraint } if id_constraint? + end + end + + def id_constraint? + @scope[:id].is_a?(Regexp) || (@scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp)) + end + + def id_constraint + @scope[:id] || @scope[:constraints][:id] + end + def canonical_action?(action, flag) flag && CANONICAL_ACTIONS.include?(action) end def shallow_scoping? - parent_resource && parent_resource.shallow? && @scope[:scope_level] == :member + shallow? && @scope[:scope_level] == :member end def path_for_action(action, path) @@ -932,7 +932,7 @@ module ActionDispatch collection_name = parent_resource.collection_name member_name = parent_resource.member_name name_prefix = "#{name_prefix}_" if name_prefix.present? - end + end case @scope[:scope_level] when :collection |