public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Added optimal formatted routes to rails, deprecating the formatted_* methods, 
and reducing routes creation by 50% [#1359 state:committed]

Signed-off-by: David Heinemeier Hansson <david@loudthinking.com>
aaronbatalion (author)
Sun Nov 23 23:24:19 -0800 2008
dhh (committer)
Wed Nov 26 01:52:05 -0800 2008
commit  fef6c32afe2276dffa0347e25808a86e7a101af1
tree    42a43392f0e478e7b752bfd885a4e91b08828487
parent  6599dd907f87875045005c3754fc7fe75c130c3e
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 *2.3.0 [Edge]*
0
 
0
+* Dropped formatted_* routes in favor of just passing in :format as an option. This cuts resource routes generation in half #1359 [aaronbatalion]
0
+
0
 * Remove support for old double-encoded cookies from the cookie store.  These values haven't been generated since before 2.1.0, and any users who have visited the app in the intervening 6 months will have had their cookie upgraded. [Koz]
0
 
0
 * Allow helpers directory to be overridden via ActionController::Base.helpers_dir #1424 [Sam Pohlenz]
...
639
640
641
642
643
 
644
645
646
647
648
...
639
640
641
 
 
642
643
 
644
645
646
0
@@ -639,10 +639,8 @@ module ActionController
0
           formatted_route_path = "#{route_path}.:format"
0
 
0
           if route_name && @set.named_routes[route_name.to_sym].nil?
0
-            map.named_route(route_name, route_path, action_options)
0
-            map.named_route("formatted_#{route_name}", formatted_route_path, action_options)
0
+            map.named_route(route_name, formatted_route_path, action_options)
0
           else
0
-            map.connect(route_path, action_options)
0
             map.connect(formatted_route_path, action_options)
0
           end
0
         end
...
34
35
36
 
 
37
38
39
...
34
35
36
37
38
39
40
41
0
@@ -34,6 +34,8 @@ module ActionController
0
       def segment_for(string)
0
         segment =
0
           case string
0
+            when  /\A\.(:format)?\// 
0
+              OptionalFormatSegment.new
0
             when /\A:(\w+)/
0
               key = $1.to_sym
0
               key == :controller ? ControllerSegment.new(key) : DynamicSegment.new(key)
...
65
66
67
68
 
69
70
71
...
65
66
67
 
68
69
70
71
0
@@ -65,7 +65,7 @@ module ActionController
0
       # rather than triggering the expensive logic in +url_for+.
0
       class PositionalArguments < Optimiser
0
         def guard_conditions
0
-          number_of_arguments = route.segment_keys.size
0
+          number_of_arguments = route.required_segment_keys.size
0
           # if they're using foo_url(:id=>2) it's one
0
           # argument, but we don't want to generate /foos/id2
0
           if number_of_arguments == 1
...
35
36
37
 
 
 
 
 
38
39
40
...
35
36
37
38
39
40
41
42
43
44
45
0
@@ -35,6 +35,11 @@ module ActionController
0
           segment.key if segment.respond_to? :key
0
         end.compact
0
       end
0
+      
0
+      def required_segment_keys
0
+        required_segments = segments.select {|seg| (!seg.optional? && !seg.is_a?(DividerSegment)) || seg.is_a?(PathSegment) }
0
+        required_segments.collect { |seg| seg.key if seg.respond_to?(:key)}.compact
0
+      end
0
 
0
       # Build a query string from the keys of the given hash. If +only_keys+
0
       # is given (as an array), only the keys indicated will be used to build
...
185
186
187
 
 
 
 
 
 
 
 
188
189
190
...
361
362
363
364
 
365
366
367
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
...
369
370
371
 
372
373
374
375
0
@@ -185,6 +185,14 @@ module ActionController
0
                 end
0
 
0
                 url_for(#{hash_access_method}(opts))
0
+                
0
+              end
0
+              #Add an alias to support the now deprecated formatted_* URL.
0
+              def formatted_#{selector}(*args)
0
+                ActiveSupport::Deprecation.warn(
1
+                  "formatted_#{selector}() has been deprecated. please pass format to the standard" +
0
+                  "#{selector}() method instead.", caller)
0
+                #{selector}(*args)
0
               end
0
               protected :#{selector}
0
             end_eval
0
@@ -361,7 +369,7 @@ module ActionController
0
           end
0
 
0
           # don't use the recalled keys when determining which routes to check
0
-          routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }]
0
+          routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
0
 
0
           routes.each do |route|
0
             results = route.__send__(method, options, merged, expire_on)
...
308
309
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
312
...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
0
@@ -308,5 +308,36 @@ module ActionController
0
         end
0
       end
0
     end
0
+    
0
+    # The OptionalFormatSegment allows for any resource route to have an optional
0
+    # :format, which decreases the amount of routes created by 50%.
0
+    class OptionalFormatSegment < DynamicSegment
0
+    
0
+      def initialize(key = nil, options = {})
0
+        super(:format, {:optional => true}.merge(options))            
0
+      end
0
+    
0
+      def interpolation_chunk
0
+        "." + super
0
+      end
0
+    
0
+      def regexp_chunk
0
+        '(\.[^/?\.]+)?'
0
+      end
0
+    
0
+      def to_s
0
+        '(.:format)?'
0
+      end
0
+    
0
+      #the value should not include the period (.)
0
+      def match_extraction(next_capture)
0
+        %[
0
+          if (m = match[#{next_capture}])
0
+            params[:#{key}] = URI.unescape(m.from(1))
0
+          end
0
+        ]
0
+      end
0
+    end
0
+    
0
   end
0
 end
...
187
188
189
190
 
191
192
193
...
316
317
318
319
 
320
321
322
...
1130
1131
1132
1133
 
1134
1135
 
1136
1137
1138
 
1139
1140
 
1141
1142
1143
...
1189
1190
1191
1192
 
1193
1194
1195
 
1196
1197
 
1198
1199
1200
...
187
188
189
 
190
191
192
193
...
316
317
318
 
319
320
321
322
...
1130
1131
1132
 
1133
1134
 
1135
1136
1137
 
1138
1139
 
1140
1141
1142
1143
...
1189
1190
1191
 
1192
1193
1194
 
1195
1196
 
1197
1198
1199
1200
0
@@ -187,7 +187,7 @@ class ResourcesTest < ActionController::TestCase
0
 
0
       assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
0
         actions.keys.each do |action|
0
-          assert_named_route "/threads/1/messages/#{action}.xml", "formatted_#{action}_thread_messages_path", :action => action, :format => 'xml'
0
+          assert_named_route "/threads/1/messages/#{action}.xml", "#{action}_thread_messages_path", :action => action, :format => 'xml'
0
         end
0
       end
0
     end
0
@@ -316,7 +316,7 @@ class ResourcesTest < ActionController::TestCase
0
       end
0
 
0
       assert_restful_named_routes_for :messages, :path_prefix => 'threads/1/', :name_prefix => 'thread_', :options => { :thread_id => '1' } do |options|
0
-        assert_named_route preview_path, :formatted_preview_new_thread_message_path, preview_options
0
+        assert_named_route preview_path, :preview_new_thread_message_path, preview_options
0
       end
0
     end
0
   end
0
@@ -1130,14 +1130,14 @@ class ResourcesTest < ActionController::TestCase
0
       end
0
 
0
       assert_named_route "#{full_path}", "#{name_prefix}#{controller_name}_path", options[:options]
0
-      assert_named_route "#{full_path}.xml", "formatted_#{name_prefix}#{controller_name}_path", options[:options].merge(:format => 'xml')
0
+      assert_named_route "#{full_path}.xml", "#{name_prefix}#{controller_name}_path", options[:options].merge(:format => 'xml')
0
       assert_named_route "#{shallow_path}/1", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1')
0
-      assert_named_route "#{shallow_path}/1.xml", "formatted_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml')
0
+      assert_named_route "#{shallow_path}/1.xml", "#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml')
0
 
0
       assert_named_route "#{full_path}/#{new_action}", "new_#{name_prefix}#{singular_name}_path", options[:options]
0
-      assert_named_route "#{full_path}/#{new_action}.xml", "formatted_new_#{name_prefix}#{singular_name}_path", options[:options].merge(:format => 'xml')
0
+      assert_named_route "#{full_path}/#{new_action}.xml", "new_#{name_prefix}#{singular_name}_path", options[:options].merge(:format => 'xml')
0
       assert_named_route "#{shallow_path}/1/#{edit_action}", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1')
0
-      assert_named_route "#{shallow_path}/1/#{edit_action}.xml", "formatted_edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml')
0
+      assert_named_route "#{shallow_path}/1/#{edit_action}.xml", "edit_#{shallow_prefix}#{singular_name}_path", options[:shallow_options].merge(:id => '1', :format => 'xml')
0
 
0
       yield options[:options] if block_given?
0
     end
0
@@ -1189,12 +1189,12 @@ class ResourcesTest < ActionController::TestCase
0
       name_prefix = options[:name_prefix]
0
 
0
       assert_named_route "#{full_path}",          "#{name_prefix}#{singleton_name}_path",                options[:options]
0
-      assert_named_route "#{full_path}.xml",      "formatted_#{name_prefix}#{singleton_name}_path",      options[:options].merge(:format => 'xml')
0
+      assert_named_route "#{full_path}.xml",      "#{name_prefix}#{singleton_name}_path",      options[:options].merge(:format => 'xml')
0
 
0
       assert_named_route "#{full_path}/new",      "new_#{name_prefix}#{singleton_name}_path",            options[:options]
0
-      assert_named_route "#{full_path}/new.xml",  "formatted_new_#{name_prefix}#{singleton_name}_path",  options[:options].merge(:format => 'xml')
0
+      assert_named_route "#{full_path}/new.xml",  "new_#{name_prefix}#{singleton_name}_path",  options[:options].merge(:format => 'xml')
0
       assert_named_route "#{full_path}/edit",     "edit_#{name_prefix}#{singleton_name}_path",           options[:options]
0
-      assert_named_route "#{full_path}/edit.xml", "formatted_edit_#{name_prefix}#{singleton_name}_path", options[:options].merge(:format => 'xml')
0
+      assert_named_route "#{full_path}/edit.xml", "edit_#{name_prefix}#{singleton_name}_path", options[:options].merge(:format => 'xml')
0
     end
0
 
0
     def assert_named_route(expected, route, options)
...
301
302
303
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
305
306
...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
0
@@ -301,6 +301,41 @@ class UrlWriterTests < ActionController::TestCase
0
     assert_generates("/image", :controller=> :image)
0
   end
0
 
0
+  def test_named_routes_with_nil_keys
0
+    add_host!
0
+    ActionController::Routing::Routes.draw do |map|
0
+      map.main '', :controller => 'posts'
0
+      map.resources :posts
0
+      map.connect ':controller/:action/:id'
0
+    end
0
+    # We need to create a new class in order to install the new named route.
0
+    kls = Class.new { include ActionController::UrlWriter }
0
+    controller = kls.new
0
+    params = {:action => :index, :controller => :posts, :format => :xml}
0
+    assert_equal("http://www.basecamphq.com/posts.xml", controller.send(:url_for, params))    
0
+    params[:format] = nil
0
+    assert_equal("http://www.basecamphq.com/", controller.send(:url_for, params))    
0
+  ensure
0
+    ActionController::Routing::Routes.load!
0
+  end
0
+
0
+  def test_formatted_url_methods_are_deprecated
0
+    ActionController::Routing::Routes.draw do |map|
0
+      map.resources :posts
0
+    end
0
+    # We need to create a new class in order to install the new named route.
0
+    kls = Class.new { include ActionController::UrlWriter }
0
+    controller = kls.new
0
+    params = {:id => 1, :format => :xml}
0
+    assert_deprecated do
0
+      assert_equal("/posts/1.xml", controller.send(:formatted_post_path, params))    
0
+    end
0
+    assert_deprecated do
0
+      assert_equal("/posts/1.xml", controller.send(:formatted_post_path, 1, :xml))    
0
+    end
0
+  ensure
0
+    ActionController::Routing::Routes.load!
0
+  end
0
   private
0
     def extract_params(url)
0
       url.split('?', 2).last.split('&')

Comments

FYI, missing a space between “standard” and the route method name in this deprecation warning text.