aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/routing/mapper.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/routing/mapper.rb')
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb128
1 files changed, 98 insertions, 30 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index ae4417b56c..e91a72cbe5 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -350,6 +350,10 @@ module ActionDispatch
scope(:constraints => constraints) { yield }
end
+ def shallow
+ scope(:shallow => true) { yield }
+ end
+
def defaults(defaults = {})
scope(:defaults => defaults) { yield }
end
@@ -374,12 +378,21 @@ module ActionDispatch
@scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
end
+ def merge_shallow_scope(parent, child)
+ parent or child
+ end
+
def merge_path_scope(parent, child)
- Mapper.normalize_path("#{parent}/#{child}")
+ parent_path = (@scope[:shallow] and child.eql?(':id')) ? parent.split('/').last : parent
+ Mapper.normalize_path "#{parent_path}/#{child}"
end
def merge_name_prefix_scope(parent, child)
- parent ? "#{parent}_#{child}" : child
+ if @scope[:shallow]
+ child
+ else
+ parent ? "#{parent}_#{child}" : child
+ end
end
def merge_module_scope(parent, child)
@@ -463,6 +476,10 @@ module ActionDispatch
name.to_s.singularize
end
+ def member_prefix
+ ':id'
+ end
+
def member_name
singular
end
@@ -509,11 +526,19 @@ module ActionDispatch
end
end
+ def nested_prefix
+ id_segment
+ end
+
def nested_options
options = { :name_prefix => member_name }
options["#{singular}_id".to_sym] = id_constraint if id_constraint?
options
end
+
+ def shallow?
+ options[:shallow]
+ end
end
class SingletonResource < Resource #:nodoc:
@@ -532,9 +557,21 @@ module ActionDispatch
end
end
+ def member_prefix
+ ''
+ end
+
def member_name
name
end
+
+ def nested_prefix
+ ''
+ end
+
+ def nested_options
+ { :name_prefix => member_name }
+ end
end
def initialize(*args) #:nodoc:
@@ -544,6 +581,7 @@ module ActionDispatch
def resource(*resources, &block)
options = resources.extract_options!
+ options = (@scope[:options] || {}).merge(options)
if apply_common_behavior_for(:resource, resources, options, &block)
return self
@@ -554,17 +592,17 @@ module ActionDispatch
scope(:path => resource.path, :controller => resource.controller) do
with_scope_level(:resource, resource) do
- scope(:name_prefix => resource.name.to_s, :as => "") do
- yield if block_given?
- end
+ yield if block_given?
- scope(resource.options) do
- get :show if resource.actions.include?(:show)
- post :create if resource.actions.include?(:create)
- put :update if resource.actions.include?(:update)
- delete :destroy if resource.actions.include?(:destroy)
- get :new, :as => resource.name if resource.actions.include?(:new)
- get :edit, :as => resource.name if resource.actions.include?(:edit)
+ with_scope_level(:member) do
+ scope(resource.options) do
+ get :show if resource.actions.include?(:show)
+ post :create if resource.actions.include?(:create)
+ put :update if resource.actions.include?(:update)
+ delete :destroy if resource.actions.include?(:destroy)
+ get :new, :as => resource.name if resource.actions.include?(:new)
+ get :edit, :as => resource.name if resource.actions.include?(:edit)
+ end
end
end
end
@@ -574,6 +612,7 @@ module ActionDispatch
def resources(*resources, &block)
options = resources.extract_options!
+ options = (@scope[:options] || {}).merge(options)
if apply_common_behavior_for(:resources, resources, options, &block)
return self
@@ -581,8 +620,12 @@ module ActionDispatch
resource = Resource.new(resources.pop, options)
- scope(:path => resource.path, :controller => resource.controller) do
+ scope(:path => resource.path, :controller => resource.controller, :shallow => resource.shallow?) do
with_scope_level(:resources, resource) do
+ if @scope[:shallow] && @scope[:name_prefix]
+ @scope[:path] = "/#{@scope[:name_prefix].pluralize}/:#{@scope[:name_prefix]}_id/#{resource.path}"
+ end
+
yield if block_given?
with_scope_level(:collection) do
@@ -596,6 +639,8 @@ module ActionDispatch
with_scope_level(:member) do
scope(':id') do
scope(resource.options) do
+ @scope[:name_prefix] = nil if @scope[:shallow]
+
get :show if resource.actions.include?(:show)
put :update if resource.actions.include?(:update)
delete :destroy if resource.actions.include?(:destroy)
@@ -622,31 +667,36 @@ module ActionDispatch
end
def member
- unless [:resources, :resource].include?(@scope[:scope_level])
- raise ArgumentError, "You can't use member action outside resources and resource scope."
+ unless resource_scope?
+ raise ArgumentError, "can't use member outside resource(s) scope"
end
- case @scope[:scope_level]
- when :resources
- with_scope_level(:member) do
- scope(':id', :name_prefix => parent_resource.member_name, :as => "") do
- yield
- end
+ with_scope_level(:member) do
+ scope(parent_resource.member_prefix, :name_prefix => parent_resource.member_name, :as => "") do
+ yield
end
- when :resource
- with_scope_level(:member) do
+ end
+ end
+
+ def new
+ unless resource_scope?
+ raise ArgumentError, "can't use new outside resource(s) scope"
+ end
+
+ with_scope_level(:new) do
+ scope(new_scope_prefix, :name_prefix => parent_resource.member_name, :as => "") do
yield
end
end
end
def nested
- unless @scope[:scope_level] == :resources
- raise ArgumentError, "can't use nested outside resources scope"
+ unless resource_scope?
+ raise ArgumentError, "can't use nested outside resource(s) scope"
end
with_scope_level(:nested) do
- scope(parent_resource.id_segment, parent_resource.nested_options) do
+ scope(parent_resource.nested_prefix, parent_resource.nested_options) do
yield
end
end
@@ -678,7 +728,7 @@ module ActionDispatch
@scope[:path] = old_path
end
else
- with_exclusive_name_prefix(action) do
+ with_exclusive_name_prefix(action_name_prefix(action, options)) do
return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action))
end
end
@@ -691,10 +741,16 @@ module ActionDispatch
return collection { match(*args) }
when :member
return member { match(*args) }
+ when :new
+ return new { match(*args) }
+ end
+
+ if @scope[:scope_level] == :resource
+ return member { match(*args) }
end
- if @scope[:scope_level] == :resources
- raise ArgumentError, "can't define route directly in resources scope"
+ if resource_scope?
+ raise ArgumentError, "can't define route directly in resource(s) scope"
end
super
@@ -716,6 +772,10 @@ module ActionDispatch
path_names[name.to_sym] || name.to_s
end
+ def action_name_prefix(action, options = {})
+ (options[:on] == :new || @scope[:scope_level] == :new) ? "#{action}_new" : action
+ end
+
def apply_common_behavior_for(method, resources, options, &block)
if resources.length > 1
resources.each { |r| send(method, r, options, &block) }
@@ -729,7 +789,7 @@ module ActionDispatch
return true
end
- if @scope[:scope_level] == :resources
+ if resource_scope?
nested do
send(method, resources.pop, options, &block)
end
@@ -739,6 +799,14 @@ module ActionDispatch
false
end
+ def new_scope_prefix
+ @scope[:path_names][:new] || 'new'
+ end
+
+ def resource_scope?
+ [:resource, :resources].include?(@scope[:scope_level])
+ end
+
def with_exclusive_name_prefix(prefix)
begin
old_name_prefix = @scope[:name_prefix]