From c5d0ef4b7c0528bfde6ffd123df87f266e13f97d Mon Sep 17 00:00:00 2001 From: Balazs Nagy Date: Fri, 12 Feb 2010 15:21:26 +0100 Subject: [PATCH] Added support for shallow nesting. Add support for :shallow => true in resources. Now it is aware of subpath shallowing too. Signed-off-by: Balazs Nagy --- actionpack/lib/action_dispatch/routing/mapper.rb | 66 ++++++++++++++++++++-- actionpack/test/dispatch/routing_test.rb | 22 +++++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 8de68b3..c058fc6 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -473,10 +473,17 @@ module ActionDispatch end resource = Resource.new(resources.pop, options) + if (options.delete(:shallow)) + @scope[:shallow] = save_scope + elsif @scope.has_key? :shallow + orig_scope = save_scope + end scope(:path => resource.name.to_s, :controller => resource.controller) do with_scope_level(:resources, resource) do - yield if block_given? + with_shallow_scope(orig_scope) do + yield if block_given? + end with_scope_level(:collection) do get :index if resource.actions.include?(:index) @@ -486,15 +493,23 @@ module ActionDispatch with_scope_level(:member) do scope(':id') do - get :show if resource.actions.include?(:show) - put :update if resource.actions.include?(:update) - delete :destroy if resource.actions.include?(:destroy) - get :edit, :as => resource.singular if resource.actions.include?(:edit) + with_shallow_scope(orig_scope) do + get :show if resource.actions.include?(:show) + put :update if resource.actions.include?(:update) + delete :destroy if resource.actions.include?(:destroy) + get :edit, :as => resource.singular if resource.actions.include?(:edit) + end end end end end + if orig_scope + restore_scope(orig_scope) + elsif @scope.has_key? :shallow + @scope.delete(:shallow) + end + self end @@ -638,6 +653,47 @@ module ActionDispatch @scope[:scope_level] = old @scope[:scope_level_resource] = old_resource end + + def save_scope + { + :path => @scope[:path], + :name_prefix => @scope[:name_prefix] + } + end + + def restore_scope(hsh) + @scope[:path] = hsh[:path] + @scope[:name_prefix] = hsh[:name_prefix] + end + + def with_shallow_scope(curr_scope) + if !block_given? + raise "with_shallow_scope expects a block" + end + _saved_scope = save_scope + shallow_scope(curr_scope) + yield + restore_scope(_saved_scope) + end + + def shallow_scope(ref_scope) + return if ref_scope.nil? + return unless @scope.has_key? :shallow + root_scope = @scope[:shallow] + return if root_scope[:path] == ref_scope[:path] + pathstart = namestart = 0 + unless @scope[:path].start_with? ref_scope[:path] + raise 'shallow_scope path mismatch' + end + pathstop, namestop = ref_scope[:path].length-1, ref_scope[:name_prefix].length-1 + if @scope[:path].start_with? root_scope[:path] + pathstart, namestart = root_scope[:path].length, root_scope[:name_prefix].length + end + @scope[:path] = @scope[:path].dup + @scope[:path][pathstart..pathstop] = '' + @scope[:name_prefix] = @scope[:name_prefix].dup + @scope[:name_prefix][namestart..namestop] = '' + end end include Base diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index bcb97e4..4775b6e 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -155,6 +155,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resources :descriptions root :to => 'projects#index' end + + # http://guides.rails.info/routing.html#shallow-nesting with a twist + resources :hosts do + resources :publishers, :shallow => true do + resources :magazines do + resources :photos + end + end + end end end @@ -719,6 +728,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + # http://guides.rails.info/routing.html#shallow-nesting with a twist + def test_shallow_nesting + with_test_routes do + assert_equal '/hosts/1', host_path(1) + assert_equal '/hosts/1/publishers', host_publishers_path(1) + assert_equal '/hosts/1/publishers/1', host_publisher_path(1, 1) + assert_equal '/hosts/1/publishers/1/magazines', host_publisher_magazines_path(1, 1) + assert_equal '/hosts/1/magazines/2', host_magazine_path(1, 2) + assert_equal '/hosts/1/magazines/2/photos', host_magazine_photos_path(1, 2) + assert_equal '/hosts/1/photos/3', host_photo_path(1, 3) + end + end + private def with_test_routes real_routes, temp_routes = ActionController::Routing::Routes, Routes -- 1.6.6.1