Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'master' into prepend-content-for

* master: (45 commits)
  use Hash#delete with a default block
  refactor options_for_select
  refactor grouped_options_for_select
  Fix a failing test
  Use the right format when a partial is missing.
  Merge pull request #5101 from ckdake/ckdake_actionview_handler_reset
  search private / protected methods in trunk ruby
  removed commented line. 3434 tests, 10531 assertions, 0 failures, 0 errors, 31 skips
  Restored ability to identify ID and Sequence from tables relying on a nonmatching sequence default value for PK.
  AM::Errors: allow :full_messages parameter for #as_json
  Remove fixture files with Windows incompatible filenames
  Integration tests support the OPTIONS http method
  Update activerecord/CHANGELOG.md
  fix some typos [ci skip]
  Documenting the :inverse_of option for associations
  add selected and disabled option to grouped select
  assigns(:foo) should not convert @foo's keys to strings if it happens to be a hash
  Fix actionpack readme weblog example
  Fix AbstractController::Base#hidden_actions comment
  Do get it right this time. Fixing the documentation around :dependent => :restrict option
  ...
  • Loading branch information...
commit e6ff135f1dbde5dcee915199116721528ab7d6e1 2 parents f7bbdcc + 563df87
DeLynn Berry authored February 20, 2012

Showing 43 changed files with 740 additions and 144 deletions. Show diff stats Hide diff stats

  1. 2  actionmailer/README.rdoc
  2. 3  actionmailer/lib/action_mailer/mail_helper.rb
  3. 5  actionpack/CHANGELOG.md
  4. 2  actionpack/README.rdoc
  5. 4  actionpack/lib/abstract_controller/base.rb
  6. 11  actionpack/lib/action_controller/metal/conditional_get.rb
  7. 2  actionpack/lib/action_controller/metal/responder.rb
  8. 14  actionpack/lib/action_dispatch/http/cache.rb
  9. 13  actionpack/lib/action_dispatch/middleware/static.rb
  10. 8  actionpack/lib/action_dispatch/testing/integration.rb
  11. 3  actionpack/lib/action_dispatch/testing/test_process.rb
  12. 10  actionpack/lib/action_view/helpers/form_helper.rb
  13. 25  actionpack/lib/action_view/helpers/form_options_helper.rb
  14. 7  actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb
  15. 1  actionpack/lib/action_view/template.rb
  16. 1  actionpack/lib/action_view/template/handlers.rb
  17. 6  actionpack/lib/sprockets/helpers/rails_helper.rb
  18. 18  actionpack/test/controller/integration_test.rb
  19. 27  actionpack/test/controller/render_test.rb
  20. 5  actionpack/test/controller/test_case_test.rb
  21. 90  actionpack/test/dispatch/static_test.rb
  22. 1  actionpack/test/fixtures/with_format.json.erb
  23. 50  actionpack/test/template/form_options_helper_test.rb
  24. 13  actionpack/test/template/render_test.rb
  25. 2  actionpack/test/template/template_test.rb
  26. 2  activemodel/CHANGELOG.md
  27. 17  activemodel/lib/active_model/errors.rb
  28. 10  activemodel/test/cases/errors_test.rb
  29. 2  activerecord/CHANGELOG.md
  30. 60  activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
  31. 2  activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  32. 60  activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  33. 5  activerecord/lib/active_record/railties/databases.rake
  34. 10  activerecord/test/cases/adapters/postgresql/schema_test.rb
  35. 21  activerecord/test/cases/connection_management_test.rb
  36. 2  activesupport/lib/active_support/core_ext/time/calculations.rb
  37. 1  railties/guides/assets/stylesheets/main.css
  38. 2  railties/guides/source/active_record_validations_callbacks.textile
  39. 105  railties/guides/source/association_basics.textile
  40. 206  railties/guides/source/engines.textile
  41. 2  railties/guides/source/layouts_and_rendering.textile
  42. 4  railties/lib/rails/engine.rb
  43. 50  railties/test/application/rake/migrations_test.rb
2  actionmailer/README.rdoc
Source Rendered
@@ -82,7 +82,7 @@ Note that every value you set with this method will get over written if you use
82 82
 
83 83
 Example:
84 84
 
85  
-  class Authenticationmailer < ActionMailer::Base
  85
+  class AuthenticationMailer < ActionMailer::Base
86 86
     default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" }
87 87
     .....
88 88
   end
3  actionmailer/lib/action_mailer/mail_helper.rb
... ...
@@ -1,7 +1,6 @@
1 1
 module ActionMailer
2 2
   module MailHelper
3  
-    # Uses Text::Format to take the text and format it, indented two spaces for
4  
-    # each line, and wrapped at 72 columns.
  3
+    # Take the text and format it, indented two spaces for each line, and wrapped at 72 columns.
5 4
     def block_format(text)
6 5
       formatted = text.split(/\n\r?\n/).collect { |paragraph|
7 6
         format_paragraph(paragraph)
5  actionpack/CHANGELOG.md
Source Rendered
... ...
@@ -1,5 +1,10 @@
1 1
 ## Rails 4.0.0 (unreleased) ##
2 2
 
  3
+*   Integration tests support the `OPTIONS` method. *Jeremy Kemper*
  4
+
  5
+*   `expires_in` accepts a `must_revalidate` flag. If true, "must-revalidate"
  6
+    is added to the Cache-Control header. *fxn*
  7
+
3 8
 *   Add `date_field` and `date_field_tag` helpers which render an `input[type="date"]` tag *Olek Janiszewski*
4 9
 
5 10
 *   Adds `image_url`, `javascript_url`, `stylesheet_url`, `audio_url`, `video_url`, and `font_url`
2  actionpack/README.rdoc
Source Rendered
@@ -218,7 +218,7 @@ A short rundown of some of the major features:
218 218
 
219 219
       def show
220 220
         # the output of the method will be cached as
221  
-        # ActionController::Base.page_cache_directory + "/weblog/show/n.html"
  221
+        # ActionController::Base.page_cache_directory + "/weblog/show.html"
222 222
         # and the web server will pick it up without even hitting Rails
223 223
       end
224 224
 
4  actionpack/lib/abstract_controller/base.rb
@@ -42,8 +42,8 @@ def internal_methods
42 42
         controller.public_instance_methods(true)
43 43
       end
44 44
 
45  
-      # The list of hidden actions to an empty array. Defaults to an
46  
-      # empty array. This can be modified by other modules or subclasses
  45
+      # The list of hidden actions. Defaults to an empty array.
  46
+      # This can be modified by other modules or subclasses
47 47
       # to specify particular actions as hidden.
48 48
       #
49 49
       # ==== Returns
11  actionpack/lib/action_controller/metal/conditional_get.rb
@@ -110,16 +110,23 @@ def stale?(record_or_options, additional_options = {})
110 110
     #
111 111
     # Examples:
112 112
     #   expires_in 20.minutes
113  
-    #   expires_in 3.hours, :public => true
  113
+    #   expires_in 3.hours, :public => true, :must_revalidate => true
114 114
     #   expires_in 3.hours, 'max-stale' => 5.hours, :public => true
115 115
     #
116 116
     # This method will overwrite an existing Cache-Control header.
117 117
     # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
  118
+    #
  119
+    # The method will also ensure a HTTP Date header for client compatibility.
118 120
     def expires_in(seconds, options = {}) #:doc:
119  
-      response.cache_control.merge!(:max_age => seconds, :public => options.delete(:public))
  121
+      response.cache_control.merge!(
  122
+        :max_age         => seconds,
  123
+        :public          => options.delete(:public),
  124
+        :must_revalidate => options.delete(:must_revalidate)
  125
+      )
120 126
       options.delete(:private)
121 127
 
122 128
       response.cache_control[:extras] = options.map {|k,v| "#{k}=#{v}"}
  129
+      response.date = Time.now unless response.date?
123 130
     end
124 131
 
125 132
     # Sets a HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should occur by the browser or
2  actionpack/lib/action_controller/metal/responder.rb
@@ -267,7 +267,7 @@ def default_action
267 267
     end
268 268
 
269 269
     def resource_errors
270  
-      respond_to?("#{format}_resource_errors") ? send("#{format}_resource_errors") : resource.errors
  270
+      respond_to?("#{format}_resource_errors", true) ? send("#{format}_resource_errors") : resource.errors
271 271
     end
272 272
 
273 273
     def json_resource_errors
14  actionpack/lib/action_dispatch/http/cache.rb
@@ -60,6 +60,20 @@ def last_modified=(utc_time)
60 60
           headers[LAST_MODIFIED] = utc_time.httpdate
61 61
         end
62 62
 
  63
+        def date
  64
+          if date_header = headers['Date']
  65
+            Time.httpdate(date_header)
  66
+          end
  67
+        end
  68
+
  69
+        def date?
  70
+          headers.include?('Date')
  71
+        end
  72
+
  73
+        def date=(utc_time)
  74
+          headers['Date'] = utc_time.httpdate
  75
+        end
  76
+
63 77
         def etag=(etag)
64 78
           key = ActiveSupport::Cache.expand_cache_key(etag)
65 79
           @etag = self[ETAG] = %("#{Digest::MD5.hexdigest(key)}")
13  actionpack/lib/action_dispatch/middleware/static.rb
... ...
@@ -1,4 +1,5 @@
1 1
 require 'rack/utils'
  2
+require 'active_support/core_ext/uri'
2 3
 
3 4
 module ActionDispatch
4 5
   class FileHandler
@@ -11,14 +12,14 @@ def initialize(root, cache_control)
11 12
     def match?(path)
12 13
       path = path.dup
13 14
 
14  
-      full_path = path.empty? ? @root : File.join(@root, ::Rack::Utils.unescape(path))
  15
+      full_path = path.empty? ? @root : File.join(@root, escape_glob_chars(unescape_path(path)))
15 16
       paths = "#{full_path}#{ext}"
16 17
 
17 18
       matches = Dir[paths]
18 19
       match = matches.detect { |m| File.file?(m) }
19 20
       if match
20 21
         match.sub!(@compiled_root, '')
21  
-        match
  22
+        ::Rack::Utils.escape(match)
22 23
       end
23 24
     end
24 25
 
@@ -32,6 +33,14 @@ def ext
32 33
         "{,#{ext},/index#{ext}}"
33 34
       end
34 35
     end
  36
+
  37
+    def unescape_path(path)
  38
+      URI.parser.unescape(path)
  39
+    end
  40
+
  41
+    def escape_glob_chars(path)
  42
+      path.gsub(/[*?{}\[\]]/, "\\\\\\&")
  43
+    end
35 44
   end
36 45
 
37 46
   class Static
8  actionpack/lib/action_dispatch/testing/integration.rb
@@ -56,6 +56,12 @@ def head(path, parameters = nil, headers = nil)
56 56
         process :head, path, parameters, headers
57 57
       end
58 58
 
  59
+      # Performs a OPTIONS request with the given parameters. See +#get+ for
  60
+      # more details.
  61
+      def options(path, parameters = nil, headers = nil)
  62
+        process :options, path, parameters, headers
  63
+      end
  64
+
59 65
       # Performs an XMLHttpRequest request with the given parameters, mirroring
60 66
       # a request from the Prototype library.
61 67
       #
@@ -312,7 +318,7 @@ def reset!
312 318
         @integration_session = Integration::Session.new(app)
313 319
       end
314 320
 
315  
-      %w(get post put head delete cookies assigns
  321
+      %w(get post put head delete options cookies assigns
316 322
          xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
317 323
         define_method(method) do |*args|
318 324
           reset! unless integration_session
3  actionpack/lib/action_dispatch/testing/test_process.rb
@@ -5,7 +5,8 @@
5 5
 module ActionDispatch
6 6
   module TestProcess
7 7
     def assigns(key = nil)
8  
-      assigns = @controller.view_assigns.with_indifferent_access
  8
+      assigns = {}.with_indifferent_access
  9
+      @controller.view_assigns.each {|k, v| assigns.regular_writer(k, v)}
9 10
       key.nil? ? assigns : assigns[key]
10 11
     end
11 12
 
10  actionpack/lib/action_view/helpers/form_helper.rb
@@ -1102,14 +1102,14 @@ def submit(value=nil, options={})
1102 1102
       #   <% end %>
1103 1103
       #
1104 1104
       # In the example above, if @post is a new record, it will use "Create Post" as
1105  
-      # submit button label, otherwise, it uses "Update Post".
  1105
+      # button label, otherwise, it uses "Update Post".
1106 1106
       #
1107  
-      # Those labels can be customized using I18n, under the helpers.submit key and accept
1108  
-      # the %{model} as translation interpolation:
  1107
+      # Those labels can be customized using I18n, under the helpers.submit key
  1108
+      # (the same as submit helper) and accept the %{model} as translation interpolation:
1109 1109
       #
1110 1110
       #   en:
1111 1111
       #     helpers:
1112  
-      #       button:
  1112
+      #       submit:
1113 1113
       #         create: "Create a %{model}"
1114 1114
       #         update: "Confirm changes to %{model}"
1115 1115
       #
@@ -1117,7 +1117,7 @@ def submit(value=nil, options={})
1117 1117
       #
1118 1118
       #   en:
1119 1119
       #     helpers:
1120  
-      #       button:
  1120
+      #       submit:
1121 1121
       #         post:
1122 1122
       #           create: "Add %{model}"
1123 1123
       #
25  actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -330,9 +330,12 @@ def options_for_select(container, selected = nil)
330 330
         container.map do |element|
331 331
           html_attributes = option_html_attributes(element)
332 332
           text, value = option_text_and_value(element).map { |item| item.to_s }
333  
-          selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
334  
-          disabled_attribute = ' disabled="disabled"' if disabled && option_value_selected?(value, disabled)
335  
-          %(<option value="#{ERB::Util.html_escape(value)}"#{selected_attribute}#{disabled_attribute}#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
  333
+
  334
+          html_attributes[:selected] = 'selected' if option_value_selected?(value, selected)
  335
+          html_attributes[:disabled] = 'disabled' if disabled && option_value_selected?(value, disabled)
  336
+          html_attributes[:value] = value
  337
+
  338
+          content_tag(:option, text, html_attributes)
336 339
         end.join("\n").html_safe
337 340
       end
338 341
 
@@ -472,16 +475,16 @@ def option_groups_from_collection_for_select(collection, group_method, group_lab
472 475
       # <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
473 476
       # wrap the output in an appropriate <tt><select></tt> tag.
474 477
       def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
475  
-        body = ''
476  
-        body << content_tag(:option, prompt, { :value => "" }, true) if prompt
  478
+        body = "".html_safe
  479
+        body.safe_concat content_tag(:option, prompt, :value => "") if prompt
477 480
 
478 481
         grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
479 482
 
480  
-        grouped_options.each do |group|
481  
-          body << content_tag(:optgroup, options_for_select(group[1], selected_key), :label => group[0])
  483
+        grouped_options.each do |label, container|
  484
+          body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), :label => label)
482 485
         end
483 486
 
484  
-        body.html_safe
  487
+        body
485 488
       end
486 489
 
487 490
       # Returns a string of option tags for pretty much any time zone in the
@@ -649,11 +652,9 @@ def collection_check_boxes(object, method, collection, value_method, text_method
649 652
 
650 653
       private
651 654
         def option_html_attributes(element)
652  
-          return "" unless Array === element
  655
+          return {} unless Array === element
653 656
 
654  
-          element.select { |e| Hash === e }.reduce({}, :merge).map do |k, v|
655  
-            " #{k}=\"#{ERB::Util.html_escape(v.to_s)}\""
656  
-          end.join
  657
+          Hash[element.select { |e| Hash === e }.reduce({}, :merge).map { |k, v| [k, ERB::Util.html_escape(v.to_s)] }]
657 658
         end
658 659
 
659 660
         def option_text_and_value(option)
7  actionpack/lib/action_view/helpers/tags/grouped_collection_select.rb
@@ -14,8 +14,13 @@ def initialize(object_name, method_name, template_object, collection, group_meth
14 14
         end
15 15
 
16 16
         def render
  17
+          option_tags_options = {
  18
+            :selected => @options.fetch(:selected) { value(@object) },
  19
+            :disabled => @options[:disabled]
  20
+          }
  21
+
17 22
           select_content_tag(
18  
-            option_groups_from_collection_for_select(@collection, @group_method, @group_label_method, @option_key_method, @option_value_method, value(@object)), @options, @html_options
  23
+            option_groups_from_collection_for_select(@collection, @group_method, @group_label_method, @option_key_method, @option_value_method, option_tags_options), @options, @html_options
19 24
           )
20 25
         end
21 26
       end
1  actionpack/lib/action_view/template.rb
@@ -163,6 +163,7 @@ def refresh(view)
163 163
       pieces  = @virtual_path.split("/")
164 164
       name    = pieces.pop
165 165
       partial = !!name.sub!(/^_/, "")
  166
+      lookup.formats = @formats
166 167
       lookup.disable_cache do
167 168
         lookup.find_template(name, [ pieces.join('/') ], partial, @locals)
168 169
       end
1  actionpack/lib/action_view/template/handlers.rb
@@ -23,6 +23,7 @@ def self.extensions
23 23
       # and should return the rendered template as a String.
24 24
       def register_template_handler(extension, handler)
25 25
         @@template_handlers[extension.to_sym] = handler
  26
+        @@template_extensions = nil
26 27
       end
27 28
 
28 29
       def template_handler_extensions
6  actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -19,9 +19,9 @@ def asset_paths
19 19
 
20 20
       def javascript_include_tag(*sources)
21 21
         options = sources.extract_options!
22  
-        debug = options.key?(:debug) ? options.delete(:debug) : debug_assets?
23  
-        body  = options.key?(:body)  ? options.delete(:body)  : false
24  
-        digest  = options.key?(:digest)  ? options.delete(:digest)  : digest_assets?
  22
+        debug   = options.delete(:debug)  { debug_assets? }
  23
+        body    = options.delete(:body)   { false }
  24
+        digest  = options.delete(:digest) { digest_assets? }
25 25
 
26 26
         sources.collect do |source|
27 27
           if debug && asset = asset_paths.asset_for(source, 'js')
18  actionpack/test/controller/integration_test.rb
@@ -105,6 +105,12 @@ def test_head
105 105
     @session.head(path,params,headers)
106 106
   end
107 107
 
  108
+  def test_options
  109
+    path = "/index"; params = "blah"; headers = {:location => 'blah'}
  110
+    @session.expects(:process).with(:options,path,params,headers)
  111
+    @session.options(path,params,headers)
  112
+  end
  113
+
108 114
   def test_xml_http_request_get
109 115
     path = "/index"; params = "blah"; headers = {:location => 'blah'}
110 116
     headers_after_xhr = headers.merge(
@@ -155,6 +161,16 @@ def test_xml_http_request_head
155 161
     @session.xml_http_request(:head,path,params,headers)
156 162
   end
157 163
 
  164
+  def test_xml_http_request_options
  165
+    path = "/index"; params = "blah"; headers = {:location => 'blah'}
  166
+    headers_after_xhr = headers.merge(
  167
+      "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
  168
+      "HTTP_ACCEPT"           => "text/javascript, text/html, application/xml, text/xml, */*"
  169
+    )
  170
+    @session.expects(:process).with(:options,path,params,headers_after_xhr)
  171
+    @session.xml_http_request(:options,path,params,headers)
  172
+  end
  173
+
158 174
   def test_xml_http_request_override_accept
159 175
     path = "/index"; params = "blah"; headers = {:location => 'blah', "HTTP_ACCEPT" => "application/xml"}
160 176
     headers_after_xhr = headers.merge(
@@ -212,7 +228,7 @@ def test_integration_methods_called
212 228
     @integration_session.stubs(:generic_url_rewriter)
213 229
     @integration_session.stubs(:process)
214 230
 
215  
-    %w( get post head put delete ).each do |verb|
  231
+    %w( get post head put delete options ).each do |verb|
216 232
       assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') }
217 233
     end
218 234
   end
27  actionpack/test/controller/render_test.rb
@@ -91,6 +91,16 @@ def conditional_hello_with_expires_in_with_public
91 91
     render :action => 'hello_world'
92 92
   end
93 93
 
  94
+  def conditional_hello_with_expires_in_with_must_revalidate
  95
+    expires_in 1.minute, :must_revalidate => true
  96
+    render :action => 'hello_world'
  97
+  end
  98
+
  99
+  def conditional_hello_with_expires_in_with_public_and_must_revalidate
  100
+    expires_in 1.minute, :public => true, :must_revalidate => true
  101
+    render :action => 'hello_world'
  102
+  end
  103
+
94 104
   def conditional_hello_with_expires_in_with_public_with_more_keys
95 105
     expires_in 1.minute, :public => true, 'max-stale' => 5.hours
96 106
     render :action => 'hello_world'
@@ -1399,6 +1409,16 @@ def test_expires_in_header_with_public
1399 1409
     assert_equal "max-age=60, public", @response.headers["Cache-Control"]
1400 1410
   end
1401 1411
 
  1412
+  def test_expires_in_header_with_must_revalidate
  1413
+    get :conditional_hello_with_expires_in_with_must_revalidate
  1414
+    assert_equal "max-age=60, private, must-revalidate", @response.headers["Cache-Control"]
  1415
+  end
  1416
+
  1417
+  def test_expires_in_header_with_public_and_must_revalidate
  1418
+    get :conditional_hello_with_expires_in_with_public_and_must_revalidate
  1419
+    assert_equal "max-age=60, public, must-revalidate", @response.headers["Cache-Control"]
  1420
+  end
  1421
+
1402 1422
   def test_expires_in_header_with_additional_headers
1403 1423
     get :conditional_hello_with_expires_in_with_public_with_more_keys
1404 1424
     assert_equal "max-age=60, public, max-stale=18000", @response.headers["Cache-Control"]
@@ -1413,6 +1433,13 @@ def test_expires_now
1413 1433
     get :conditional_hello_with_expires_now
1414 1434
     assert_equal "no-cache", @response.headers["Cache-Control"]
1415 1435
   end
  1436
+
  1437
+  def test_date_header_when_expires_in
  1438
+    time = Time.mktime(2011,10,30)
  1439
+    Time.stubs(:now).returns(time)
  1440
+    get :conditional_hello_with_expires_in
  1441
+    assert_equal Time.now.httpdate, @response.headers["Date"]
  1442
+  end
1416 1443
 end
1417 1444
 
1418 1445
 class LastModifiedRenderTest < ActionController::TestCase
5  actionpack/test/controller/test_case_test.rb
@@ -119,6 +119,7 @@ def delete_cookie
119 119
 
120 120
     def test_assigns
121 121
       @foo = "foo"
  122
+      @foo_hash = {:foo => :bar}
122 123
       render :nothing => true
123 124
     end
124 125
 
@@ -292,6 +293,10 @@ def test_assigns
292 293
     assert_equal "foo", assigns("foo")
293 294
     assert_equal "foo", assigns[:foo]
294 295
     assert_equal "foo", assigns["foo"]
  296
+
  297
+    # but the assigned variable should not have its own keys stringified
  298
+    expected_hash = { :foo => :bar }
  299
+    assert_equal expected_hash, assigns(:foo_hash)
295 300
   end
296 301
 
297 302
   def test_view_assigns
90  actionpack/test/dispatch/static_test.rb
... ...
@@ -1,5 +1,6 @@
1 1
 # encoding: utf-8
2 2
 require 'abstract_unit'
  3
+require 'rbconfig'
3 4
 
4 5
 module StaticTests
5 6
   def test_serves_dynamic_content
@@ -35,6 +36,87 @@ def test_served_static_file_with_non_english_filename
35 36
     assert_html "means hello in Japanese\n", get("/foo/#{Rack::Utils.escape("こんにちは.html")}")
36 37
   end
37 38
 
  39
+
  40
+  def test_serves_static_file_with_exclamation_mark_in_filename
  41
+    with_static_file "/foo/foo!bar.html" do |file|
  42
+      assert_html file, get("/foo/foo%21bar.html")
  43
+      assert_html file, get("/foo/foo!bar.html")
  44
+    end
  45
+  end
  46
+
  47
+  def test_serves_static_file_with_dollar_sign_in_filename
  48
+    with_static_file "/foo/foo$bar.html" do |file|
  49
+      assert_html file, get("/foo/foo%24bar.html")
  50
+      assert_html file, get("/foo/foo$bar.html")
  51
+    end
  52
+  end
  53
+
  54
+  def test_serves_static_file_with_ampersand_in_filename
  55
+    with_static_file "/foo/foo&bar.html" do |file|
  56
+      assert_html file, get("/foo/foo%26bar.html")
  57
+      assert_html file, get("/foo/foo&bar.html")
  58
+    end
  59
+  end
  60
+
  61
+  def test_serves_static_file_with_apostrophe_in_filename
  62
+    with_static_file "/foo/foo'bar.html" do |file|
  63
+      assert_html file, get("/foo/foo%27bar.html")
  64
+      assert_html file, get("/foo/foo'bar.html")
  65
+    end
  66
+  end
  67
+
  68
+  def test_serves_static_file_with_parentheses_in_filename
  69
+    with_static_file "/foo/foo(bar).html" do |file|
  70
+      assert_html file, get("/foo/foo%28bar%29.html")
  71
+      assert_html file, get("/foo/foo(bar).html")
  72
+    end
  73
+  end
  74
+
  75
+  def test_serves_static_file_with_plus_sign_in_filename
  76
+    with_static_file "/foo/foo+bar.html" do |file|
  77
+      assert_html file, get("/foo/foo%2Bbar.html")
  78
+      assert_html file, get("/foo/foo+bar.html")
  79
+    end
  80
+  end
  81
+
  82
+  def test_serves_static_file_with_comma_in_filename
  83
+    with_static_file "/foo/foo,bar.html" do |file|
  84
+      assert_html file, get("/foo/foo%2Cbar.html")
  85
+      assert_html file, get("/foo/foo,bar.html")
  86
+    end
  87
+  end
  88
+
  89
+  def test_serves_static_file_with_semi_colon_in_filename
  90
+    with_static_file "/foo/foo;bar.html" do |file|
  91
+      assert_html file, get("/foo/foo%3Bbar.html")
  92
+      assert_html file, get("/foo/foo;bar.html")
  93
+    end
  94
+  end
  95
+
  96
+  def test_serves_static_file_with_at_symbol_in_filename
  97
+    with_static_file "/foo/foo@bar.html" do |file|
  98
+      assert_html file, get("/foo/foo%40bar.html")
  99
+      assert_html file, get("/foo/foo@bar.html")
  100
+    end
  101
+  end
  102
+
  103
+  # Windows doesn't allow \ / : * ? " < > | in filenames
  104
+  unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
  105
+    def test_serves_static_file_with_colon
  106
+      with_static_file "/foo/foo:bar.html" do |file|
  107
+        assert_html file, get("/foo/foo%3Abar.html")
  108
+        assert_html file, get("/foo/foo:bar.html")
  109
+      end
  110
+    end
  111
+
  112
+    def test_serves_static_file_with_asterisk
  113
+      with_static_file "/foo/foo*bar.html" do |file|
  114
+        assert_html file, get("/foo/foo%2Abar.html")
  115
+        assert_html file, get("/foo/foo*bar.html")
  116
+      end
  117
+    end
  118
+  end
  119
+
38 120
   private
39 121
 
40 122
     def assert_html(body, response)
@@ -45,6 +127,14 @@ def assert_html(body, response)
45 127
     def get(path)
46 128
       Rack::MockRequest.new(@app).request("GET", path)
47 129
     end
  130
+
  131
+    def with_static_file(file)
  132
+      path = "#{FIXTURE_LOAD_PATH}/public" + file
  133
+      File.open(path, "wb+") { |f| f.write(file) }
  134
+      yield file
  135
+    ensure
  136
+      File.delete(path)
  137
+    end
48 138
 end
49 139
 
50 140
 class StaticTest < ActiveSupport::TestCase
1  actionpack/test/fixtures/with_format.json.erb
... ...
@@ -0,0 +1 @@
  1
+<%= render :partial => 'missing', :formats => [:json] %>
50  actionpack/test/template/form_options_helper_test.rb
@@ -182,16 +182,16 @@ def test_array_options_for_string_include_in_other_string_bug_fix
182 182
 
183 183
   def test_hash_options_for_select
184 184
     assert_dom_equal(
185  
-      "<option value=\"&lt;Kroner&gt;\">&lt;DKR&gt;</option>\n<option value=\"Dollar\">$</option>",
186  
-      options_for_select("$" => "Dollar", "<DKR>" => "<Kroner>").split("\n").sort.join("\n")
  185
+      "<option value=\"Dollar\">$</option>\n<option value=\"&lt;Kroner&gt;\">&lt;DKR&gt;</option>",
  186
+      options_for_select("$" => "Dollar", "<DKR>" => "<Kroner>").split("\n").join("\n")
187 187
     )
188 188
     assert_dom_equal(
189  
-      "<option value=\"&lt;Kroner&gt;\">&lt;DKR&gt;</option>\n<option value=\"Dollar\" selected=\"selected\">$</option>",
190  
-      options_for_select({ "$" => "Dollar", "<DKR>" => "<Kroner>" }, "Dollar").split("\n").sort.join("\n")
  189
+      "<option value=\"Dollar\" selected=\"selected\">$</option>\n<option value=\"&lt;Kroner&gt;\">&lt;DKR&gt;</option>",
  190
+      options_for_select({ "$" => "Dollar", "<DKR>" => "<Kroner>" }, "Dollar").split("\n").join("\n")
191 191
     )
192 192
     assert_dom_equal(
193  
-      "<option value=\"&lt;Kroner&gt;\" selected=\"selected\">&lt;DKR&gt;</option>\n<option value=\"Dollar\" selected=\"selected\">$</option>",
194  
-      options_for_select({ "$" => "Dollar", "<DKR>" => "<Kroner>" }, [ "Dollar", "<Kroner>" ]).split("\n").sort.join("\n")
  193
+      "<option value=\"Dollar\" selected=\"selected\">$</option>\n<option value=\"&lt;Kroner&gt;\" selected=\"selected\">&lt;DKR&gt;</option>",
  194
+      options_for_select({ "$" => "Dollar", "<DKR>" => "<Kroner>" }, [ "Dollar", "<Kroner>" ]).split("\n").join("\n")
195 195
     )
196 196
   end
197 197
 
@@ -1056,36 +1056,36 @@ def test_options_for_select_with_element_attributes_and_selection_array
1056 1056
   end
1057 1057
 
1058 1058
   def test_option_html_attributes_from_without_hash
1059  
-    assert_dom_equal(
1060  
-      "",
  1059
+    assert_equal(
  1060
+      {},
1061 1061
       option_html_attributes([ 'foo', 'bar' ])
1062 1062
     )
1063 1063
   end
1064 1064
 
1065 1065
   def test_option_html_attributes_with_single_element_hash
1066  
-    assert_dom_equal(
1067  
-      " class=\"fancy\"",
  1066
+    assert_equal(
  1067
+      {:class => 'fancy'},
1068 1068
       option_html_attributes([ 'foo', 'bar', { :class => 'fancy' } ])
1069 1069
     )
1070 1070
   end
1071 1071
 
1072 1072
   def test_option_html_attributes_with_multiple_element_hash
1073  
-    assert_dom_equal(
1074  
-      " class=\"fancy\" onclick=\"alert('Hello World');\"",
  1073
+    assert_equal(
  1074
+      {:class => 'fancy', 'onclick' => "alert('Hello World');"},
1075 1075
       option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ])
1076 1076
     )
1077 1077
   end
1078 1078
 
1079 1079
   def test_option_html_attributes_with_multiple_hashes
1080  
-    assert_dom_equal(
1081  
-      " class=\"fancy\" onclick=\"alert('Hello World');\"",
  1080
+    assert_equal(
  1081
+      {:class => 'fancy', 'onclick' => "alert('Hello World');"},
1082 1082
       option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ])
1083 1083
     )
1084 1084
   end
1085 1085
 
1086 1086
   def test_option_html_attributes_with_special_characters
1087  
-    assert_dom_equal(
1088  
-      " onclick=\"alert(&quot;&lt;code&gt;&quot;)\"",
  1087
+    assert_equal(
  1088
+      {:onclick => "alert(&quot;&lt;code&gt;&quot;)"},
1089 1089
       option_html_attributes([ 'foo', 'bar', { :onclick => %(alert("<code>")) } ])
1090 1090
     )
1091 1091
   end
@@ -1100,6 +1100,24 @@ def test_grouped_collection_select
1100 1100
     )
1101 1101
   end
1102 1102
 
  1103
+  def test_grouped_collection_select_with_selected
  1104
+    @post = Post.new
  1105
+
  1106
+    assert_dom_equal(
  1107
+      %Q{<select id="post_origin" name="post[origin]"><optgroup label="&lt;Africa&gt;"><option value="&lt;sa&gt;">&lt;South Africa&gt;</option>\n<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option value="dk" selected="selected">Denmark</option>\n<option value="ie">Ireland</option></optgroup></select>},
  1108
+      grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, :selected => 'dk')
  1109
+    )
  1110
+  end
  1111
+
  1112
+  def test_grouped_collection_select_with_disabled_value
  1113
+    @post = Post.new
  1114
+
  1115
+    assert_dom_equal(
  1116
+      %Q{<select id="post_origin" name="post[origin]"><optgroup label="&lt;Africa&gt;"><option value="&lt;sa&gt;">&lt;South Africa&gt;</option>\n<option value="so">Somalia</option></optgroup><optgroup label="Europe"><option disabled="disabled" value="dk">Denmark</option>\n<option value="ie">Ireland</option></optgroup></select>},
  1117
+      grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, :disabled => 'dk')
  1118
+    )
  1119
+  end
  1120
+
1103 1121
   def test_grouped_collection_select_under_fields_for
1104 1122
     @post = Post.new
1105 1123
     @post.origin = 'dk'
13  actionpack/test/template/render_test.rb
@@ -51,6 +51,13 @@ def test_render_template_with_format
51 51
     assert_match "<error>No Comment</error>", @view.render(:template => "comments/empty", :formats => [:xml])
52 52
   end
53 53
 
  54
+  def test_render_template_with_a_missing_partial_of_another_format
  55
+    assert_raise ActionView::Template::Error, "Missing partial /missing with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder]}" do
  56
+      @view.lookup_context.freeze_formats([:html])
  57
+      @view.render(:template => "with_format", :formats => [:json])
  58
+    end
  59
+  end
  60
+
54 61
   def test_render_file_with_locale
55 62
     assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => [:de])
56 63
     assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => :de)
@@ -299,6 +306,12 @@ def test_render_inline_with_locals_and_compilable_custom_type
299 306
     ActionView::Template.register_template_handler :foo, CustomHandler
300 307
     assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo)
301 308
   end
  309
+  
  310
+  def test_render_knows_about_types_registered_when_extensions_are_checked_earlier_in_initialization
  311
+    ActionView::Template::Handlers.extensions
  312
+    ActionView::Template.register_template_handler :foo, CustomHandler
  313
+    assert ActionView::Template::Handlers.extensions.include?(:foo)
  314
+  end
302 315
 
303 316
   def test_render_ignores_templates_with_malformed_template_handlers
304 317
     ActiveSupport::Deprecation.silence do
2  actionpack/test/template/template_test.rb
@@ -11,6 +11,8 @@ def disable_cache
11 11
 
12 12
     def find_template(*args)
13 13
     end
  14
+
  15
+    attr_writer :formats
14 16
   end
15 17
 
16 18
   class Context
2  activemodel/CHANGELOG.md
Source Rendered
... ...
@@ -1,3 +1,5 @@
  1
+*   `AM::Errors#to_json`: support `:full_messages` parameter *Bogdan Gusiev*
  2
+
1 3
 *   Trim down Active Model API by removing `valid?` and `errors.full_messages` *José Valim*
2 4
 
3 5
 ## Rails 3.2.0 (January 20, 2012) ##
17  activemodel/lib/active_model/errors.rb
@@ -206,12 +206,23 @@ def to_xml(options={})
206 206
     end
207 207
 
208 208
     # Returns an Hash that can be used as the JSON representation for this object.
  209
+    # Options:
  210
+    # * <tt>:full_messages</tt> - determines if json object should contain 
  211
+    #   full messages or not. Default: <tt>false</tt>.
209 212
     def as_json(options=nil)
210  
-      to_hash
  213
+      to_hash(options && options[:full_messages])
211 214
     end
212 215
 
213  
-    def to_hash
214  
-      messages.dup
  216
+    def to_hash(full_messages = false)
  217
+      if full_messages
  218
+        messages = {}
  219
+        self.messages.each do |attribute, array|
  220
+          messages[attribute] = array.map{|message| full_message(attribute, message) }
  221
+        end
  222
+        messages
  223
+      else
  224
+        self.messages.dup
  225
+      end
215 226
     end
216 227
 
217 228
     # Adds +message+ to the error messages on +attribute+. More than one error can be added to the same
10  activemodel/test/cases/errors_test.rb
@@ -184,6 +184,16 @@ def test_has_key?
184 184
     assert_equal ["is invalid"], hash[:email]
185 185
   end
186 186
 
  187
+  test 'should return a JSON hash representation of the errors with full messages' do
  188
+    person = Person.new
  189
+    person.errors.add(:name, "can not be blank")
  190
+    person.errors.add(:name, "can not be nil")
  191
+    person.errors.add(:email, "is invalid")
  192
+    hash = person.errors.as_json(:full_messages => true)
  193
+    assert_equal ["name can not be blank", "name can not be nil"], hash[:name]
  194
+    assert_equal ["email is invalid"], hash[:email]
  195
+  end
  196
+
187 197
   test "generate_message should work without i18n_scope" do
188 198
     person = Person.new
189 199
     assert !Person.respond_to?(:i18n_scope)
2  activerecord/CHANGELOG.md
Source Rendered
@@ -130,7 +130,7 @@
130 130
 *   PostgreSQL hstore types are automatically deserialized from the database.
131 131
 
132 132
 
133  
-## Rails 3.2.1 (unreleased) ##
  133
+## Rails 3.2.1 (January 26, 2012) ##
134 134
 
135 135
 *   The threshold for auto EXPLAIN is ignored if there's no logger. *fxn*
136 136
 
60  activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -328,16 +328,18 @@ def active_connections
328 328
     # ActiveRecord::Base.connection_handler. Active Record models use this to
329 329
     # determine that connection pool that they should use.
330 330
     class ConnectionHandler
331  
-      attr_reader :connection_pools
332  
-
333  
-      def initialize(pools = {})
  331
+      def initialize(pools = Hash.new { |h,k| h[k] = {} })
334 332
         @connection_pools = pools
335  
-        @class_to_pool    = {}
  333
+        @class_to_pool    = Hash.new { |h,k| h[k] = {} }
  334
+      end
  335
+
  336
+      def connection_pools
  337
+        @connection_pools[Process.pid]
336 338
       end
337 339
 
338 340
       def establish_connection(name, spec)
339  
-        @connection_pools[spec] ||= ConnectionAdapters::ConnectionPool.new(spec)
340  
-        @class_to_pool[name] = @connection_pools[spec]
  341
+        set_pool_for_spec spec, ConnectionAdapters::ConnectionPool.new(spec)
  342
+        set_class_to_pool name, connection_pools[spec]
341 343
       end
342 344
 
343 345
       # Returns true if there are any active connections among the connection
@@ -350,21 +352,21 @@ def active_connections?
350 352
       # and also returns connections to the pool cached by threads that are no
351 353
       # longer alive.
352 354
       def clear_active_connections!
353  
-        @connection_pools.each_value {|pool| pool.release_connection }
  355
+        connection_pools.each_value {|pool| pool.release_connection }
354 356
       end
355 357
 
356 358
       # Clears the cache which maps classes.
357 359
       def clear_reloadable_connections!
358  
-        @connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
  360
+        connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
359 361
       end
360 362
 
361 363
       def clear_all_connections!
362  
-        @connection_pools.each_value {|pool| pool.disconnect! }
  364
+        connection_pools.each_value {|pool| pool.disconnect! }
363 365
       end
364 366
 
365 367
       # Verify active connections.
366 368
       def verify_active_connections! #:nodoc:
367  
-        @connection_pools.each_value {|pool| pool.verify_active_connections! }
  369
+        connection_pools.each_value {|pool| pool.verify_active_connections! }
368 370
       end
369 371
 
370 372
       # Locate the connection of the nearest super class. This can be an
@@ -388,21 +390,53 @@ def connected?(klass)
388 390
       # can be used as an argument for establish_connection, for easily
389 391
       # re-establishing the connection.
390 392
       def remove_connection(klass)
391  
-        pool = @class_to_pool.delete(klass.name)
  393
+        pool = class_to_pool.delete(klass.name)
392 394
         return nil unless pool
393 395
 
394  
-        @connection_pools.delete pool.spec
  396
+        connection_pools.delete pool.spec
395 397
         pool.automatic_reconnect = false
396 398
         pool.disconnect!
397 399
         pool.spec.config
398 400
       end
399 401
 
400 402
       def retrieve_connection_pool(klass)
401  
-        pool = @class_to_pool[klass.name]
  403
+        pool = get_pool_for_class klass.name
402 404
         return pool if pool
403 405
         return nil if ActiveRecord::Model == klass
404 406
         retrieve_connection_pool klass.active_record_super
405 407
       end
  408
+
  409
+      private
  410
+
  411
+      def class_to_pool
  412
+        @class_to_pool[Process.pid]
  413
+      end
  414
+
  415
+      def set_pool_for_spec(spec, pool)
  416
+        @connection_pools[Process.pid][spec] = pool
  417
+      end
  418
+
  419
+      def set_class_to_pool(name, pool)
  420
+        @class_to_pool[Process.pid][name] = pool
  421
+        pool
  422
+      end
  423
+
  424
+      def get_pool_for_class(klass)
  425
+        @class_to_pool[Process.pid].fetch(klass) {
  426
+          c_to_p = @class_to_pool.values.find { |class_to_pool|
  427
+            class_to_pool[klass]
  428
+          }
  429
+
  430
+          if c_to_p
  431
+            pool = c_to_p[klass]
  432
+            pool = ConnectionAdapters::ConnectionPool.new pool.spec
  433
+            set_pool_for_spec pool.spec, pool
  434
+            set_class_to_pool klass, pool
  435
+          else
  436
+            set_class_to_pool klass, nil
  437
+          end
  438
+        }
  439
+      end
406 440
     end
407 441
 
408 442
     class ConnectionManagement
2  activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -119,7 +119,7 @@ def clear
119 119
 
120 120
         private
121 121
         def cache
122  
-          @cache[$$]
  122
+          @cache[Process.pid]
123 123
         end
124 124
       end
125 125
 
60  activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -359,7 +359,7 @@ def delete(sql_key)
359 359
 
360 360
         private
361 361
         def cache
362  
-          @cache[$$]
  362
+          @cache[Process.pid]
363 363
         end
364 364
 
365 365
         def dealloc(key)
@@ -1032,26 +1032,46 @@ def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
1032 1032
       def pk_and_sequence_for(table) #:nodoc:
1033 1033
         # First try looking for a sequence with a dependency on the
1034 1034
         # given table's primary key.
1035  
-        result = exec_query(<<-end_sql, 'SCHEMA').rows.first
1036  
-          SELECT attr.attname, ns.nspname, seq.relname
1037  
-          FROM pg_class seq
1038  
-          INNER JOIN pg_depend dep ON seq.oid = dep.objid
1039  
-          INNER JOIN pg_attribute attr ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
1040  
-          INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
1041  
-          INNER JOIN pg_namespace ns ON seq.relnamespace = ns.oid
1042  
-          WHERE seq.relkind  = 'S'
1043  
-            AND cons.contype = 'p'
1044  
-            AND dep.refobjid = '#{quote_table_name(table)}'::regclass
  1035
+        result = query(<<-end_sql, 'PK and serial sequence')[0]
  1036
+          SELECT attr.attname, seq.relname
  1037
+          FROM pg_class      seq,
  1038
+               pg_attribute  attr,
  1039
+               pg_depend     dep,
  1040
+               pg_namespace  name,
  1041
+               pg_constraint cons
  1042
+          WHERE seq.oid           = dep.objid
  1043
+            AND seq.relkind       = 'S'
  1044
+            AND attr.attrelid     = dep.refobjid
  1045
+            AND attr.attnum       = dep.refobjsubid
  1046
+            AND attr.attrelid     = cons.conrelid
  1047
+            AND attr.attnum       = cons.conkey[1]
  1048
+            AND cons.contype      = 'p'
  1049
+            AND dep.refobjid      = '#{quote_table_name(table)}'::regclass
1045 1050
         end_sql
1046 1051
 
1047  
-        # [primary_key, sequence]
1048  
-        if result.second ==  'public' then
1049  
-          sequence = result.last
1050  
-        else
1051  
-          sequence = result.second+'.'+result.last
  1052
+        if result.nil? or result.empty?
  1053
+          # If that fails, try parsing the primary key's default value.
  1054
+          # Support the 7.x and 8.0 nextval('foo'::text) as well as
  1055
+          # the 8.1+ nextval('foo'::regclass).
  1056
+          result = query(<<-end_sql, 'PK and custom sequence')[0]
  1057
+            SELECT attr.attname,
  1058
+              CASE
  1059
+                WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
  1060
+                  substr(split_part(def.adsrc, '''', 2),
  1061
+                         strpos(split_part(def.adsrc, '''', 2), '.')+1)
  1062
+                ELSE split_part(def.adsrc, '''', 2)
  1063
+              END
  1064
+            FROM pg_class       t
  1065
+            JOIN pg_attribute   attr ON (t.oid = attrelid)
  1066
+            JOIN pg_attrdef     def  ON (adrelid = attrelid AND adnum = attnum)
  1067
+            JOIN pg_constraint  cons ON (conrelid = adrelid AND adnum = conkey[1])
  1068
+            WHERE t.oid = '#{quote_table_name(table)}'::regclass
  1069
+              AND cons.contype = 'p'
  1070
+              AND def.adsrc ~* 'nextval'
  1071
+          end_sql
1052 1072
         end
1053 1073
 
1054  
-        [result.first, sequence]
  1074
+        [result.first, result.last]
1055 1075
       rescue
1056 1076
         nil
1057 1077
       end
@@ -1238,7 +1258,11 @@ def exec_cache(sql, binds)
1238 1258
             # prepared statements whose return value may have changed is
1239 1259
             # FEATURE_NOT_SUPPORTED.  Check here for more details:
1240 1260
             # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
1241  
-            code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
  1261
+            begin
  1262
+              code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
  1263
+            rescue
  1264
+              raise e
  1265
+            end
1242 1266
             if FEATURE_NOT_SUPPORTED == code
1243 1267
               @statements.delete sql_key(sql)
1244 1268
               retry
5  activerecord/lib/active_record/railties/databases.rake
@@ -207,11 +207,12 @@ db_namespace = namespace :db do
207 207
         next  # means "return" for rake task
208 208
       end
209 209
       db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
  210
+      db_list.map! { |version| "%.3d" % version }
210 211
       file_list = []
211 212
       ActiveRecord::Migrator.migrations_paths.each do |path|
212 213
         Dir.foreach(path) do |file|
213  
-          # only files matching "20091231235959_some_name.rb" pattern
214  
-          if match_data = /^(\d{14})_(.+)\.rb$/.match(file)
  214
+          # match "20091231235959_some_name.rb" and "001_some_name.rb" pattern
  215
+          if match_data = /^(\d{3,})_(.+)\.rb$/.match(file)
215 216
             status = db_list.delete(match_data[1]) ? 'up' : 'down'
216 217
             file_list << [status, match_data[1], match_data[2].humanize]
217 218
           end
10  activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -24,6 +24,8 @@ class SchemaTest < ActiveRecord::TestCase
24 24
     'moment timestamp without time zone default now()'
25 25
   ]
26 26
   PK_TABLE_NAME = 'table_with_pk'
  27
+  UNMATCHED_SEQUENCE_NAME = 'unmatched_primary_key_default_value_seq'
  28
+  UNMATCHED_PK_TABLE_NAME = 'table_with_unmatched_sequence_for_pk'
27 29
 
28 30
   class Thing1 < ActiveRecord::Base
29 31
     self.table_name = "test_schema.things"
@@ -60,6 +62,8 @@ def setup
60 62
     @connection.execute "CREATE INDEX #{INDEX_D_NAME} ON #{SCHEMA_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_D_COLUMN} DESC);"
61 63
     @connection.execute "CREATE INDEX #{INDEX_D_NAME} ON #{SCHEMA2_NAME}.#{TABLE_NAME}  USING btree (#{INDEX_D_COLUMN} DESC);"
62 64
     @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{PK_TABLE_NAME} (id serial primary key)"
  65
+    @connection.execute "CREATE SEQUENCE #{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}"
  66
+    @connection.execute "CREATE TABLE #{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME} (id integer NOT NULL DEFAULT nextval('#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}'::regclass), CONSTRAINT unmatched_pkey PRIMARY KEY (id))"
63 67
   end
64 68
 
65 69
   def teardown
@@ -241,12 +245,12 @@ def test_primary_key_raises_error_if_table_not_found_on_schema_search_path
241 245
   def test_pk_and_sequence_for_with_schema_specified
242 246
     [
243 247
       %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"),
244  
-      %(#{SCHEMA_NAME}."#{PK_TABLE_NAME}"),
245  
-      %(#{SCHEMA_NAME}.#{PK_TABLE_NAME})
  248
+      %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
246 249
     ].each do |given|
247 250
       pk, seq = @connection.pk_and_sequence_for(given)
248 251
       assert_equal 'id', pk, "primary key should be found when table referenced as #{given}"
249  
-      assert_equal "#{SCHEMA_NAME}.#{PK_TABLE_NAME}_id_seq", seq, "sequence name should be found when table referenced as #{given}"
  252
+      assert_equal "#{PK_TABLE_NAME}_id_seq", seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}")
  253
+      assert_equal "#{UNMATCHED_SEQUENCE_NAME}", seq, "sequence name should be found when table referenced as #{given}" if given ==  %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
250 254
     end
251 255
   end
252 256
 
21  activerecord/test/cases/connection_management_test.rb
@@ -26,6 +26,27 @@ def setup
26 26
         assert ActiveRecord::Base.connection_handler.active_connections?
27 27
       end
28 28
 
  29
+      def test_connection_pool_per_pid