Ticket #8469: inferencing_url_helpers.diff
| File inferencing_url_helpers.diff, 12.9 kB (added by protocool, 2 years ago) |
|---|
-
actionpack/test/controller/inferencing_helpers_test.rb
old new 1 require File.dirname(__FILE__) + '/../abstract_unit' 2 require File.join(File.dirname(__FILE__), 'inferencing_helpers_controller') 3 4 class InferencingHelpersBaseTest < Test::Unit::TestCase 5 include ActionView::Helpers::UrlHelper 6 7 def setup 8 @request = ActionController::TestRequest.new 9 @response = ActionController::TestResponse.new 10 @controller = InferencingHelpersController.new 11 end 12 13 def test_truth; assert true; end 14 15 protected 16 def with_nested_resource_expectation 17 with_routing do |set| 18 set.draw do |map| 19 # NOTE - we set the name_prefix to nil so that the 20 # controller's show_xxx methods are a little less noisy 21 map.resources :widgets do |widget| 22 widget.resources :flanges, :name_prefix => nil do |flange| 23 flange.resources :grommets, :name_prefix => nil 24 end 25 end 26 # Make sure our get() calls can route properly 27 map.inferencing_helpers 'inferencing_helpers/:action', :controller => 'inferencing_helpers' 28 end 29 yield 30 assert_equal expected_result, @response.body unless expected_result.nil? 31 end 32 end 33 end 34 35 class InferencingHelpersFlangeTest < InferencingHelpersBaseTest 36 def test_specified_positional_path 37 with_nested_resource_expectation { get :show_specified_positional_path } 38 end 39 40 def test_segments_specified_only_in_options 41 with_nested_resource_expectation { get :show_segments_specified_only_in_options } 42 end 43 44 def test_inferred_positional_path 45 with_nested_resource_expectation { get :show_inferred_positional_path } 46 end 47 48 def test_instance_id_inference 49 with_nested_resource_expectation { get :show_instance_id_inference } 50 end 51 52 def test_inference_precedence 53 with_nested_resource_expectation { get :show_inference_precedence } 54 end 55 56 protected 57 def expected_result 58 '/widgets/a_widget/flanges/a_flange' 59 end 60 end 61 62 class InferencingHelpersGrommetTest < InferencingHelpersBaseTest 63 def test_deep_inferred_positional_path 64 with_nested_resource_expectation { get :show_deep_inferred_positional_path } 65 end 66 67 def test_positionals_always_overrides_instance_variables 68 with_nested_resource_expectation { get :show_positionals_always_overrides_instance_variables } 69 end 70 71 def test_options_always_overrides_instance_variables 72 with_nested_resource_expectation { get :show_options_always_overrides_instance_variables } 73 end 74 75 def test_positionals_always_overrides_options 76 with_nested_resource_expectation { get :show_positionals_always_overrides_options } 77 end 78 79 protected 80 def expected_result 81 '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 82 end 83 end 84 85 class InferencingHelpersAdditionalParamsTest < InferencingHelpersBaseTest 86 def test_additional_params_with_positionals 87 with_nested_resource_expectation { get :show_additional_params_with_positionals } 88 end 89 90 def test_additional_params_with_segments_only_in_options 91 with_nested_resource_expectation { get :show_additional_params_with_just_options } 92 end 93 94 def test_additional_params_with_mixed_segments 95 with_nested_resource_expectation { get :show_additional_params_with_mixed_args } 96 end 97 98 def test_additional_params_with_segments_inferred 99 with_nested_resource_expectation { get :show_additional_params_with_segments_inferred } 100 end 101 102 protected 103 def expected_result 104 '/widgets/a_widget/flanges/a_flange/grommets?another=param' 105 end 106 end 107 108 class InferencingHelpersExtraTest < InferencingHelpersBaseTest 109 def test_collection_helpers_need_no_arguments 110 with_nested_resource_expectation do 111 get :show_collection_helpers_need_no_arguments 112 assert_equal '/widgets/a_widget/flanges/a_flange/grommets', @response.body 113 end 114 end 115 116 def test_explosion_because_id_segment_is_never_inferred 117 with_nested_resource_expectation do 118 assert_raises ActionController::RoutingError do 119 get :show_explosion_because_id_segment_is_never_inferred 120 end 121 end 122 end 123 124 def test_explosion_because_no_inference_strategy_available 125 with_nested_resource_expectation do 126 assert_raises ActionController::RoutingError do 127 get :show_explosion_because_no_inference_strategy_available 128 end 129 end 130 end 131 132 def test_explosion_because_too_many_positionals 133 with_nested_resource_expectation do 134 assert_raises ArgumentError do 135 get :show_explosion_because_too_many_positionals 136 end 137 end 138 end 139 140 protected 141 def expected_result 142 nil # no automatic assertion please 143 end 144 end -
actionpack/test/controller/inferencing_helpers_controller.rb
old new 1 class InferencingHelpersController < ActionController::Base 2 self.view_paths = [ "#{File.dirname(__FILE__)}/../fixtures/" ] 3 4 def self.controller_path; 'inferencing_helpers' end 5 def rescue_action(e) raise e end 6 7 # Test routes are set up as follows: 8 # map.resources :widgets do |widget| 9 # widget.resources :flanges, :name_prefix => nil do |flange| 10 # flange.resources :grommets, :name_prefix => nil 11 # end 12 # end 13 14 def show_specified_positional_path 15 # test expects '/widgets/a_widget/flanges/a_flange' 16 render :inline => "<%= flange_path('a_widget', 'a_flange') %>" 17 end 18 19 def show_segments_specified_only_in_options 20 # test expects '/widgets/a_widget/flanges/a_flange' 21 render :inline => "<%= flange_path(:widget_id => 'a_widget', :id => 'a_flange') %>" 22 end 23 24 def show_inferred_positional_path 25 # test expects '/widgets/a_widget/flanges/a_flange' 26 @widget = 'a_widget' 27 render :inline => "<%= flange_path('a_flange') %>" 28 end 29 30 def show_instance_id_inference 31 # test expects '/widgets/a_widget/flanges/a_flange' 32 @widget_id = 'a_widget' 33 render :inline => "<%= flange_path('a_flange') %>" 34 end 35 36 def show_inference_precedence 37 # test expects '/widgets/a_widget/flanges/a_flange' 38 @widget_id = 'bogus_widget' 39 @widget = 'a_widget' 40 render :inline => "<%= flange_path('a_flange') %>" 41 end 42 43 def show_deep_inferred_positional_path 44 # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 45 @widget = 'a_widget' 46 render :inline => "<%= grommet_path('a_flange','a_grommet') %>" 47 end 48 49 def show_positionals_always_overrides_instance_variables 50 # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 51 @widget = 'bogus_widget' 52 @flange = 'bogus_flange' 53 render :inline => "<%= grommet_path('a_widget', 'a_flange', 'a_grommet') %>" 54 end 55 56 def show_options_always_overrides_instance_variables 57 # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 58 @widget = 'bogus_widget' 59 @flange = 'bogus_flange' 60 render :inline => "<%= grommet_path('a_grommet', :widget_id => 'a_widget', :flange_id => 'a_flange') %>" 61 end 62 63 def show_positionals_always_overrides_options 64 # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 65 render :inline => "<%= grommet_path('a_widget', 'a_flange', 'a_grommet', :widget_id => 'bogus_widget', :flange_id => 'bogus_flange') %>" 66 end 67 68 def show_additional_params_with_positionals 69 # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 70 render :inline => "<%= grommets_path('a_widget', 'a_flange', :another => 'param') %>" 71 end 72 73 def show_additional_params_with_just_options 74 # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 75 render :inline => "<%= grommets_path(:widget_id => 'a_widget', :flange_id => 'a_flange', :another => 'param') %>" 76 end 77 78 def show_additional_params_with_mixed_args 79 # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 80 render :inline => "<%= grommets_path('a_flange', :widget_id => 'a_widget', :another => 'param') %>" 81 end 82 83 def show_additional_params_with_segments_inferred 84 # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 85 @widget = 'a_widget' 86 @flange = 'a_flange' 87 render :inline => "<%= grommets_path(:another => 'param') %>" 88 end 89 90 def show_collection_helpers_need_no_arguments 91 # test expects '/widgets/a_widget/flanges/a_flange/grommets' 92 @widget = 'a_widget' 93 @flange = 'a_flange' 94 render :inline => "<%= grommets_path() %>" 95 end 96 97 def show_explosion_because_id_segment_is_never_inferred 98 # test expects ActionController::RoutingError 99 @widget = 'a_widget' 100 @flange = 'a_flange' 101 @grommet = @id = @grommet_id = 'a_grommet' 102 render :inline => "<%= grommet_path() %>" 103 end 104 105 def show_explosion_because_no_inference_strategy_available 106 # test expects ActionController::RoutingError 107 # @widget is required by the route but is missing here 108 @flange = 'a_flange' 109 render :inline => "<%= grommet_path('a_grommet') %>" 110 end 111 112 def show_explosion_because_too_many_positionals 113 # test expects ArgumentError 114 render :inline => "<%= grommet_path('a_widget', 'a_flange', 'a_grommet', 'extra_positional') %>" 115 end 116 end -
actionpack/lib/action_controller/routing.rb
old new 1129 1129 1130 1130 def define_url_helper(route, name, kind, options) 1131 1131 selector = url_helper_name(name, kind) 1132 1132 hash_access_method = hash_access_name(name, kind) 1133 1133 1134 # The segment keys used for positional paramters 1134 1135 segment_keys = route.segments.collect do |segment| 1135 1136 segment.key if segment.respond_to? :key 1136 1137 end.compact 1137 hash_access_method = hash_access_name(name, kind) 1138 1138 1139 # Build the inference cases for each positional parameter 1140 inference_cases = [] 1141 segment_keys.each_with_index do |segment_key, index| 1142 next if segment_key == :id # never infer :id 1143 inference_cases << build_url_helper_inference_case(segment_key, index) 1144 end 1145 1139 1146 @module.send :module_eval, <<-end_eval # We use module_eval to avoid leaks 1140 def #{selector}(*args) 1141 opts = if args.empty? || Hash === args.first 1142 args.first || {} 1147 def #{selector}(*args) 1148 opts = #{hash_access_method}(Hash === args.last ? args.pop : nil) 1149 raise ArgumentError, "expected a maximum of #{segment_keys.length} positional arguments for route" if args.length > #{segment_keys.length} 1150 1151 offset = #{segment_keys.length} - args.length 1152 #{segment_keys.inspect}.each_with_index do |key, index| 1153 if (index - offset) >= 0 1154 # supplied positional args always take precedence 1155 opts[key] = args[index - offset] 1143 1156 else 1144 # allow ordered parameters to be associated with corresponding 1145 # dynamic segments, so you can do 1146 # 1147 # foo_url(bar, baz, bang) 1148 # 1149 # instead of 1150 # 1151 # foo_url(:bar => bar, :baz => baz, :bang => bang) 1152 args.zip(#{segment_keys.inspect}).inject({}) do |h, (v, k)| 1153 h[k] = v 1154 h 1157 # never overwrite an explicitly passed param with an inferred one 1158 next if opts.has_key?(key) 1159 case index 1160 #{inference_cases} 1161 when nil 1162 # bogus when condition to stop ruby from complaining at compile time 1163 # for routes that have no inference cases 1155 1164 end 1156 1165 end 1157 1158 url_for(#{hash_access_method}(opts))1159 1166 end 1167 url_for(opts) 1168 end 1160 1169 end_eval 1170 1161 1171 @module.send(:protected, selector) 1162 1172 helpers << selector 1163 1173 end 1164 1174 1175 def build_url_helper_inference_case(key, index) 1176 key_without_id = key.to_s.gsub(/_id$/,'').to_sym 1177 <<-end_eval 1178 when #{index} 1179 if inferred_val = @#{key_without_id} || @#{key} 1180 opts[key] = inferred_val 1181 end 1182 end_eval 1183 end 1165 1184 end 1166 1185 1167 1186 attr_accessor :routes, :named_routes