diff options
79 files changed, 518 insertions, 109 deletions
@@ -67,7 +67,7 @@ end platforms :jruby do gem 'json' - gem 'activerecord-jdbcsqlite3-adapter', '>= 1.2.0' + gem 'activerecord-jdbcsqlite3-adapter', '>= 1.2.7' # This is needed by now to let tests work on JRuby # TODO: When the JRuby guys merge jruby-openssl in @@ -75,8 +75,8 @@ platforms :jruby do gem 'jruby-openssl' group :db do - gem 'activerecord-jdbcmysql-adapter', '>= 1.2.0' - gem 'activerecord-jdbcpostgresql-adapter', '>= 1.2.0' + gem 'activerecord-jdbcmysql-adapter', '>= 1.2.7' + gem 'activerecord-jdbcpostgresql-adapter', '>= 1.2.7' end end diff --git a/RAILS_VERSION b/RAILS_VERSION index 734a2ff309..d883a10059 100644 --- a/RAILS_VERSION +++ b/RAILS_VERSION @@ -1 +1 @@ -3.2.13.rc2 +3.2.13 diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index 3bc15fd5a1..ce37730c44 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -3,7 +3,7 @@ * No changes. -## Rails 3.2.13 (Feb 17, 2013) ## +## Rails 3.2.13 (Mar 18, 2013) ## * No changes. diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index ba8a058f84..00f0516066 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -3,7 +3,7 @@ module ActionMailer MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index f1eb9e84f6..89029af3e9 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,9 +1,45 @@ ## unreleased ## -* No changes. +* Fix assets loading performance in 3.2.13. + + Issue #8756 uses Sprockets for resolving files that already exist on disk, + for those files their extensions don't need to be rewritten. + + Fixes #9803. + + *Fred Wu* + +* Fix `ActionController#action_missing` not being called. + Fixes #9799. + + *Janko Luin* + +* `ActionView::Helpers::NumberHelper#number_to_human` returns the number unaltered when + the units hash does not contain the needed key, e.g. when the number provided is less + than the largest key provided. + + Examples: + + number_to_human(123, units: {}) # => 123 + number_to_human(123, units: { thousand: 'k' }) # => 123 + + Fixes #9269. + Backport #9347. + + *Michael Hoffman* + +* Include I18n locale fallbacks in view lookup. + Fixes GH#3512. + + *Juan Barreneche* + +* Fix `ActionDispatch::Request#formats` when the Accept request-header is an + empty string. Fix #7774 [Backport #8977, #9541] + + *Soylent + Maxime Réty* -## Rails 3.2.13 (Feb 17, 2013) ## +## Rails 3.2.13 (Mar 18, 2013) ## * Fix incorrectly appended square brackets to a multiple select box if an explicit name has been given and it already ends with "[]". @@ -43,7 +79,7 @@ *Sergey Nartimov* -* Eagerly populate the http method loookup cache so local project inflections do +* Eagerly populate the http method lookup cache so local project inflections do not interfere with use of underscore method ( and we don't need locks ) *Aditya Sanghi* diff --git a/actionpack/lib/action_controller/metal/hide_actions.rb b/actionpack/lib/action_controller/metal/hide_actions.rb index 109484d88c..1ded166491 100644 --- a/actionpack/lib/action_controller/metal/hide_actions.rb +++ b/actionpack/lib/action_controller/metal/hide_actions.rb @@ -28,7 +28,7 @@ module ActionController end def visible_action?(action_name) - action_methods.include?(action_name) + not hidden_actions.include?(action_name) end # Overrides AbstractController::Base#action_methods to remove any methods diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index bc6828a805..dc58166f78 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -20,7 +20,12 @@ module ActionController ActiveSupport::Notifications.subscribe("render_template.action_view") do |name, start, finish, id, payload| path = payload[:layout] - @layouts[path] += 1 + if path + @layouts[path] += 1 + if path =~ /^layouts\/(.*)/ + @layouts[$1] += 1 + end + end end ActiveSupport::Notifications.subscribe("!render_template.action_view") do |name, start, finish, id, payload| @@ -56,6 +61,15 @@ module ActionController # # assert that the "new" view template was rendered # assert_template "new" # + # # assert that the layout 'admin' was rendered + # assert_template :layout => 'admin' + # assert_template :layout => 'layouts/admin' + # assert_template :layout => :admin + # + # # assert that no layout was rendered + # assert_template :layout => nil + # assert_template :layout => false + # # # assert that the "_customer" partial was rendered twice # assert_template :partial => '_customer', :count => 2 # @@ -88,17 +102,18 @@ module ActionController end end when Hash - if expected_layout = options[:layout] + if options.key?(:layout) + expected_layout = options[:layout] msg = build_message(message, "expecting layout <?> but action rendered <?>", expected_layout, @layouts.keys) case expected_layout - when String - assert(@layouts.keys.include?(expected_layout), msg) + when String, Symbol + assert(@layouts.keys.include?(expected_layout.to_s), msg) when Regexp assert(@layouts.keys.any? {|l| l =~ expected_layout }, msg) - when nil + when nil, false assert(@layouts.empty?, msg) end end @@ -125,7 +140,7 @@ module ActionController options[:partial], @partials.keys) assert(@partials.include?(expected_partial), msg) end - else + elsif options.key?(:partial) assert @partials.empty?, "Expected no partials to be rendered" end diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index af06bffa16..994e11563d 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -66,7 +66,7 @@ module HTML # A regular expression of the valid characters used to separate protocols like # the ':' in 'http://foo.com' - self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/ + self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i # Specifies a Set of HTML attributes that can have URIs. self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc)) @@ -110,8 +110,8 @@ module HTML style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ') # gauntlet - if style !~ /^([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*$/ || - style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*$/ + if style !~ /\A([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*\z/ || + style !~ /\A(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*\z/ return '' end @@ -122,7 +122,7 @@ module HTML elsif shorthand_css_properties.include?(prop.split('-')[0].downcase) unless val.split().any? do |keyword| !allowed_css_keywords.include?(keyword) && - keyword !~ /^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$/ + keyword !~ /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/ end clean << prop + ': ' + val + ';' end @@ -171,7 +171,7 @@ module HTML def contains_bad_protocols?(attr_name, value) uri_attributes.include?(attr_name) && - (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first.downcase)) + (value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip)) end end end diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 5c48a60469..42f14bc1e9 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -98,8 +98,8 @@ module ActionDispatch BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/ def valid_accept_header - (xhr? && (accept || content_mime_type)) || - (accept && accept !~ BROWSER_LIKE_ACCEPTS) + (xhr? && (accept.present? || content_mime_type)) || + (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS) end def use_accept_header diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 6b272704ea..d71b21efc3 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -67,8 +67,6 @@ module ActionDispatch private def normalize_options! - path_without_format = @path.sub(/\(\.:format\)$/, '') - @options.merge!(default_controller_and_action) requirements.each do |name, requirement| diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb index 1ae910183f..f319266765 100644 --- a/actionpack/lib/action_pack/version.rb +++ b/actionpack/lib/action_pack/version.rb @@ -3,7 +3,7 @@ module ActionPack MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index b627c77dca..ad86d13456 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -360,7 +360,7 @@ module ActionView end - STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze + STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb] # Formats the bytes in +number+ into a more understandable # representation (e.g., giving it 1500 yields 1.5 KB). This @@ -452,7 +452,7 @@ module ActionView end DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion, - -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze + -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto} # Pretty prints (formats and approximates) a number in a way it # is more readable by humans (eg.: 1200000000 becomes "1.2 @@ -593,7 +593,7 @@ module ActionView unit = case units when Hash - units[DECIMAL_UNITS[display_exponent]] + units[DECIMAL_UNITS[display_exponent]] || '' when String, Symbol I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i) else diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb index 33b508e9b5..1a656ed37f 100644 --- a/actionpack/lib/action_view/lookup_context.rb +++ b/actionpack/lib/action_view/lookup_context.rb @@ -44,7 +44,13 @@ module ActionView module Accessors #:nodoc: end - register_detail(:locale) { [I18n.locale, I18n.default_locale].uniq } + register_detail(:locale) do + locales = [I18n.locale] + locales.concat(I18n.fallbacks[I18n.locale]) if I18n.respond_to? :fallbacks + locales << I18n.default_locale + locales.uniq! + locales + end register_detail(:formats) { Mime::SET.symbols } register_detail(:handlers){ Template::Handlers.extensions } @@ -97,7 +103,7 @@ module ActionView # Helpers related to template lookup using the lookup context information. module ViewPaths - attr_reader :view_paths + attr_reader :view_paths, :html_fallback_for_js # Whenever setting view paths, makes a copy so we can manipulate then in # instance objects as we wish. @@ -194,7 +200,10 @@ module ActionView def formats=(values) if values values.concat(default_formats) if values.delete "*/*" - values << :html if values == [:js] + if values == [:js] + values << :html + @html_fallback_for_js = true + end end super(values) end diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb index 0b5d3785d4..b79b89e142 100644 --- a/actionpack/lib/action_view/renderer/abstract_renderer.rb +++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb @@ -37,5 +37,11 @@ module ActionView def instrument(name, options={}) ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield } end + + def prepend_formats(formats) + formats = Array(formats) + return if formats.empty? || @lookup_context.html_fallback_for_js + @lookup_context.formats = formats | @lookup_context.formats + end end end diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 71fa05ab3e..f3300e470b 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -281,6 +281,8 @@ module ActionView @block = block @details = extract_details(options) + prepend_formats(options[:formats]) + if String === partial @object = options[:object] @path = partial diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb index a27d5dd1b1..d15e75637a 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionpack/lib/action_view/renderer/template_renderer.rb @@ -10,9 +10,10 @@ module ActionView template = determine_template(options) context = @lookup_context + prepend_formats(template.formats) + unless context.rendered_format - context.formats = template.formats unless template.formats.empty? - context.rendered_format = context.formats.first + context.rendered_format = template.formats.first || formats.last end render_template(template, options[:layout], options[:locals]) diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 51f0cbb2da..243c2e5e50 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -163,7 +163,7 @@ module Sprockets source elsif source_ext.blank? "#{source}.#{ext}" - elsif exact_match_present?(source) + elsif File.exists?(source) || exact_match_present?(source) source else "#{source}.#{ext}" diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 5252e43c25..3b5a515e84 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -76,6 +76,11 @@ class ActionPackAssertionsController < ActionController::Base render "test/hello_world", :layout => "layouts/standard" end + def render_with_layout_and_partial + @variable_for_layout = nil + render "test/hello_world_with_partial", :layout => "layouts/standard" + end + def session_stuffing session['xmas'] = 'turkey' render :text => "ho ho ho" @@ -483,11 +488,43 @@ class AssertTemplateTest < ActionController::TestCase end end + def test_fails_expecting_no_layout + get :render_with_layout + assert_raise(ActiveSupport::TestCase::Assertion) do + assert_template :layout => nil + end + end + def test_passes_with_correct_layout get :render_with_layout assert_template :layout => "layouts/standard" end + def test_passes_with_layout_and_partial + get :render_with_layout_and_partial + assert_template :layout => "layouts/standard" + end + + def test_passed_with_no_layout + get :hello_world + assert_template :layout => nil + end + + def test_passed_with_no_layout_false + get :hello_world + assert_template :layout => false + end + + def test_passes_with_correct_layout_without_layouts_prefix + get :render_with_layout + assert_template :layout => "standard" + end + + def test_passes_with_correct_layout_symbol + get :render_with_layout + assert_template :layout => :standard + end + def test_assert_template_reset_between_requests get :hello_world assert_template 'test/hello_world' diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index affa9a6add..a652d8ffad 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -86,6 +86,12 @@ end class RecordIdentifierController < ActionController::Base end +class ActionMissingController < ActionController::Base + def action_missing(action) + render :text => "Response for #{action}" + end +end + class ControllerClassTests < ActiveSupport::TestCase def test_controller_path @@ -196,6 +202,12 @@ class PerformActionTest < ActionController::TestCase assert_raise(AbstractController::ActionNotFound) { get :hidden_action } assert_raise(AbstractController::ActionNotFound) { get :another_hidden_action } end + + def test_action_missing_should_work + use_controller ActionMissingController + get :arbitrary_action + assert_equal "Response for arbitrary_action", @response.body + end end class UrlOptionsTest < ActionController::TestCase diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb index 41ff2f3809..a5fc3f614a 100644 --- a/actionpack/test/controller/localized_templates_test.rb +++ b/actionpack/test/controller/localized_templates_test.rb @@ -19,4 +19,13 @@ class LocalizedTemplatesTest < ActionController::TestCase get :hello_world assert_equal "Hello World", @response.body end + + def test_use_fallback_locales + I18n.locale = :"de-AT" + I18n.backend.class.send(:include, I18n::Backend::Fallbacks) + I18n.fallbacks[:"de-AT"] = [:de] + + get :hello_world + assert_equal "Gutten Tag", @response.body + end end
\ No newline at end of file diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index dfd3ddbfa6..222cdfde1f 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -481,6 +481,15 @@ class RequestTest < ActiveSupport::TestCase request.expects(:parameters).at_least_once.returns({}) assert_equal [ Mime::HTML ], request.formats + request = stub_request 'HTTP_ACCEPT' => '' + request.expects(:parameters).at_least_once.returns({}) + assert_equal [Mime::HTML], request.formats + + request = stub_request 'HTTP_ACCEPT' => '', + 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" + request.expects(:parameters).at_least_once.returns({}) + assert_equal [Mime::JS], request.formats + request = stub_request 'CONTENT_TYPE' => 'application/xml; charset=UTF-8', 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" request.expects(:parameters).at_least_once.returns({}) diff --git a/actionpack/test/fixtures/test/_changing_priority.html.erb b/actionpack/test/fixtures/test/_changing_priority.html.erb new file mode 100644 index 0000000000..3225efc49a --- /dev/null +++ b/actionpack/test/fixtures/test/_changing_priority.html.erb @@ -0,0 +1 @@ +HTML
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_changing_priority.json.erb b/actionpack/test/fixtures/test/_changing_priority.json.erb new file mode 100644 index 0000000000..7fa41dce66 --- /dev/null +++ b/actionpack/test/fixtures/test/_changing_priority.json.erb @@ -0,0 +1 @@ +JSON
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_first_json_partial.json.erb b/actionpack/test/fixtures/test/_first_json_partial.json.erb new file mode 100644 index 0000000000..790ee896db --- /dev/null +++ b/actionpack/test/fixtures/test/_first_json_partial.json.erb @@ -0,0 +1 @@ +<%= render :partial => "test/second_json_partial" %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/_json_change_priority.json.erb b/actionpack/test/fixtures/test/_json_change_priority.json.erb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/test/_json_change_priority.json.erb diff --git a/actionpack/test/fixtures/test/_second_json_partial.json.erb b/actionpack/test/fixtures/test/_second_json_partial.json.erb new file mode 100644 index 0000000000..5ebb7f1afd --- /dev/null +++ b/actionpack/test/fixtures/test/_second_json_partial.json.erb @@ -0,0 +1 @@ +Third level
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/change_priorty.html.erb b/actionpack/test/fixtures/test/change_priorty.html.erb new file mode 100644 index 0000000000..5618977d05 --- /dev/null +++ b/actionpack/test/fixtures/test/change_priorty.html.erb @@ -0,0 +1,2 @@ +<%= render :partial => "test/json_change_priority", formats: :json %> +HTML Template, but <%= render :partial => "test/changing_priority" %> partial
\ No newline at end of file diff --git a/actionpack/test/fixtures/test/hello_world_with_partial.html.erb b/actionpack/test/fixtures/test/hello_world_with_partial.html.erb new file mode 100644 index 0000000000..ec31545356 --- /dev/null +++ b/actionpack/test/fixtures/test/hello_world_with_partial.html.erb @@ -0,0 +1,2 @@ +Hello world! +<%= render '/test/partial' %> diff --git a/actionpack/test/fixtures/test/html_template.html.erb b/actionpack/test/fixtures/test/html_template.html.erb new file mode 100644 index 0000000000..1bbc2b7f09 --- /dev/null +++ b/actionpack/test/fixtures/test/html_template.html.erb @@ -0,0 +1 @@ +<%= render :partial => "test/first_json_partial", formats: :json %>
\ No newline at end of file diff --git a/actionpack/test/template/html-scanner/sanitizer_test.rb b/actionpack/test/template/html-scanner/sanitizer_test.rb index 844484ee47..dee60c9d00 100644 --- a/actionpack/test/template/html-scanner/sanitizer_test.rb +++ b/actionpack/test/template/html-scanner/sanitizer_test.rb @@ -176,6 +176,7 @@ class SanitizerTest < ActionController::TestCase %(<IMG SRC="jav
ascript:alert('XSS');">), %(<IMG SRC="jav
ascript:alert('XSS');">), %(<IMG SRC="  javascript:alert('XSS');">), + %(<IMG SRC="javascript:alert('XSS');">), %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i| define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do assert_sanitized img_hack, "<img>" @@ -256,6 +257,11 @@ class SanitizerTest < ActionController::TestCase assert_equal '', sanitize_css(raw) end + def test_should_sanitize_across_newlines + raw = %(\nwidth:\nexpression(alert('XSS'));\n) + assert_equal '', sanitize_css(raw) + end + def test_should_sanitize_img_vbscript assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />' end @@ -276,6 +282,15 @@ class SanitizerTest < ActionController::TestCase assert_sanitized "<span class=\"\\", "<span class=\"\\\">" end + def test_x03a + assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>" + assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>" + assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">) + assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>" + assert_sanitized %(<a href="javascript:alert('XSS');">), "<a>" + assert_sanitized %(<a href="http://legit">), %(<a href="http://legit">) + end + protected def assert_sanitized(input, expected = nil) @sanitizer ||= HTML::WhiteListSanitizer.new diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb index 8d679aac1d..37ce3cf6b6 100644 --- a/actionpack/test/template/number_helper_test.rb +++ b/actionpack/test/template/number_helper_test.rb @@ -251,6 +251,11 @@ class NumberHelperTest < ActionView::TestCase assert_equal '4.5 tens', number_to_human(45, :units => {:unit => "", :ten => ' tens '}) end + def test_number_to_human_with_custom_units_that_are_missing_the_needed_key + assert_equal '123', number_to_human(123, :units => {:thousand => 'k'}) + assert_equal '123', number_to_human(123, :units => {}) + end + def test_number_to_human_with_custom_format assert_equal '123 times Thousand', number_to_human(123456, :format => "%n times %u") volume = {:unit => "ml", :thousand => "lt", :million => "m3"} diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index b907e3297b..f20b1c358e 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -54,6 +54,16 @@ module RenderTestCases assert_equal "Hello world", @view.render(:template => "test/one", :formats => [:html]) end + def test_render_partial_implicitly_use_format_of_the_rendered_partial + @view.lookup_context.formats = [:html] + assert_equal "Third level", @view.render(:template => "test/html_template") + end + + def test_render_partial_use_last_prepended_format_for_partials_with_the_same_names + @view.lookup_context.formats = [:html] + assert_equal "\nHTML Template, but JSON partial", @view.render(:template => "test/change_priorty") + end + def test_render_template_with_a_missing_partial_of_another_format @view.lookup_context.formats = [:html] assert_raise ActionView::Template::Error, "Missing partial /missing with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder]}" do diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index 93832c7bd9..1ad9bcab5a 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -277,6 +277,15 @@ class SprocketsHelperTest < ActionView::TestCase assert_nothing_raised { javascript_include_tag('foo.min') } end + test "assets that exist on filesystem don't need to go through Sprockets" do + @config.assets.digest = false + @config.assets.debug = true + + Rails.application.assets.expects(:resolve).never + + asset_paths.asset_for(FIXTURES.join("sprockets/app/javascripts/foo.min.js"), 'min') + end + test "stylesheet path through asset_path" do assert_match %r{/assets/application-[0-9a-f]+.css}, asset_path(:application, :ext => "css") diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 1464f52066..470e76b7d3 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -3,7 +3,7 @@ * No changes. -## Rails 3.2.13 (Feb 17, 2013) ## +## Rails 3.2.13 (Mar 18, 2013) ## * Specify type of singular association during serialization *Steve Klabnik* diff --git a/activemodel/lib/active_model/version.rb b/activemodel/lib/active_model/version.rb index dbc3811276..ec0efc72b7 100644 --- a/activemodel/lib/active_model/version.rb +++ b/activemodel/lib/active_model/version.rb @@ -3,7 +3,7 @@ module ActiveModel MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 0618c71e7b..5e5e1490c4 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,4 +1,43 @@ -## Rails 3.2.13 (Feb 17, 2013) ## +## unreleased ## + +* Removed warning when `auto_explain_threshold_in_seconds` is set and the + connection adapter doesn't support explain. + This is causing a regression since the Active Record Railtie is trying to + connect to the development database in the application boot. + + *Rafael Mendonça França* + +* Do not reset `inheritance_column` when it's set explicitly. + Backport of #5327. + + *kennyj + Fred Wu* + +* Fix a problem wrong exception is occured + when raising no translatable exception in PostgreSQL. + + *kennyj* + +* Resets the postgres search path in the structure.sql after the structure + is dumped in order to find schema_migrations table when multiples schemas + are used. + Fixes #9796. + + *Juan M. Cuello + Dembskiy Alexander* + +* Reload the association target if it's stale. `@stale_state` should be nil + when a model isn't saved. + Fixes #7526. + + *Larry Lv* + +* Don't read CSV files during execution of `db:fixtures:load`. CSV support for + fixtures was removed some time ago but the task was still loading them, even + though later the code was looking for the related yaml file instead. + + *kennyj* + + +## Rails 3.2.13 (Mar 18, 2013) ## * Chaining multiple preloaded scopes will correctly preload all the scopes at the same time. @@ -10,7 +49,7 @@ *Steve Klabnik* -* Fix overriding of attributes by default_scope on `ActiveRecord::Base#dup`. +* Fix overriding of attributes by `default_scope` on `ActiveRecord::Base#dup`. *Hiroshige UMINO* @@ -228,6 +267,16 @@ *Victor Costan* +* `#pluck` can be used on a relation with `select` clause. + Fixes #7551. + Backport of #8176. + + Example: + + Topic.select([:approved, :id]).order(:id).pluck(:id) + + *Yves Senn* + * Use `nil?` instead of `blank?` to check whether dynamic finder with a bang should raise RecordNotFound. Fixes #7238. diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index ab0d888b16..99f307922e 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -46,6 +46,7 @@ module ActiveRecord @loaded = false IdentityMap.remove(target) if IdentityMap.enabled? && target @target = nil + @stale_state = nil end # Reloads the \target and returns +self+ on success. @@ -128,16 +129,21 @@ module ActiveRecord # This method is abstract in the sense that it relies on +find_target+, # which is expected to be provided by descendants. # - # If the \target is already \loaded it is just returned. Thus, you can call - # +load_target+ unconditionally to get the \target. + # If the \target is stale(the target no longer points to the record(s) that the + # relevant foreign_key(s) refers to.), force reload the \target. + # + # Otherwise if the \target is already \loaded it is just returned. Thus, you can + # call +load_target+ unconditionally to get the \target. # # ActiveRecord::RecordNotFound is rescued within the method, and it is # not reraised. The proxy is \reset and +nil+ is the return value. def load_target - if find_target? + if (@stale_state && stale_target?) || find_target? begin if IdentityMap.enabled? && association_class && association_class.respond_to?(:base_class) @target = IdentityMap.get(association_class, owner[reflection.foreign_key]) + elsif @stale_state && stale_target? + @target = find_target end rescue NameError nil diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 97f531d064..52c67df646 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -72,7 +72,7 @@ module ActiveRecord end def stale_state - owner[reflection.foreign_key].to_s + owner[reflection.foreign_key] && owner[reflection.foreign_key].to_s end end end diff --git a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb index 2ee5dbbd70..88ce03a3cd 100644 --- a/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb @@ -27,7 +27,8 @@ module ActiveRecord end def stale_state - [super, owner[reflection.foreign_type].to_s] + foreign_key = super + foreign_key && [foreign_key.to_s, owner[reflection.foreign_type].to_s] end end end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index 4cb7b56b57..e052b00403 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -56,8 +56,7 @@ module ActiveRecord through_options[:include] = options[:include] || options[:source] through_options[:conditions] = options[:conditions] end - - through_options[:order] = options[:order] + through_options[:order] = options[:order] if options.has_key?(:order) end through_options diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index fd0e90aaf0..be890e5767 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -62,7 +62,7 @@ module ActiveRecord # properly support stale-checking for nested associations. def stale_state if through_reflection.macro == :belongs_to - owner[through_reflection.foreign_key].to_s + owner[through_reflection.foreign_key] && owner[through_reflection.foreign_key].to_s end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index ddb6896257..6a5cff6acd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -42,8 +42,8 @@ module ActiveRecord # Represents the schema of an SQL table in an abstract way. This class # provides methods for manipulating the schema representation. # - # Inside migration files, the +t+ object in +create_table+ and - # +change_table+ is actually of this type: + # Inside migration files, the +t+ object in +create_table+ + # is actually of this type: # # class SomeMigration < ActiveRecord::Migration # def up diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 8806693397..cbbb195458 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -1144,7 +1144,9 @@ module ActiveRecord UNIQUE_VIOLATION = "23505" def translate_exception(exception, message) - case exception.result.error_field(PGresult::PG_DIAG_SQLSTATE) + return exception unless exception.respond_to?(:result) + + case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE) when UNIQUE_VIOLATION RecordNotUnique.new(message, exception) when FOREIGN_KEY_VIOLATION diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 1517e5ec17..e10e6b4aa8 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -173,6 +173,7 @@ module ActiveRecord def inheritance_column=(value) @original_inheritance_column = inheritance_column @inheritance_column = value.to_s + @explicit_inheritance_column = true end def set_inheritance_column(value = nil, &block) #:nodoc: @@ -300,7 +301,8 @@ module ActiveRecord connection.schema_cache.clear_table_cache!(table_name) if table_exists? @column_names = @content_columns = @column_defaults = @columns = @columns_hash = nil - @dynamic_methods_hash = @inheritance_column = nil + @dynamic_methods_hash = nil + @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column @arel_engine = @relation = nil end diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 055d27d85c..13b7c6e214 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -83,13 +83,6 @@ module ActiveRecord end end - initializer "active_record.validate_explain_support" do |app| - if app.config.active_record[:auto_explain_threshold_in_seconds] && - !ActiveRecord::Base.connection.supports_explain? - warn "auto_explain_threshold_in_seconds is set but will be ignored because your adapter does not support this feature. Please unset the configuration to avoid this warning." - end - end - # Expose database runtime to controller for logging. initializer "active_record.log_runtime" do |app| require "active_record/railties/controller_runtime" diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 8f7c7f6b00..b8aed49854 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -355,7 +355,7 @@ db_namespace = namespace :db do base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact - (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.{yml,csv}"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file| + (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file| ActiveRecord::Fixtures.create_fixtures(fixtures_dir, fixture_file) end end @@ -427,6 +427,7 @@ db_namespace = namespace :db do end `pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(config['database'])}` raise 'Error dumping database' if $?.exitstatus == 1 + File.open(filename, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" } when /sqlite/ dbfile = config['database'] `sqlite3 #{dbfile} .schema > #{filename}` diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 4b3b30d6ed..ae1a57545e 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -464,7 +464,7 @@ module ActiveRecord node.left.relation.name == table_name } - Hash[equalities.map { |where| [where.left.name, where.right] }] + Hash[equalities.map { |where| [where.left.name, where.right] }].with_indifferent_access end def scope_for_create diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index b31fdfd981..413b81cc69 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -20,7 +20,7 @@ module ActiveRecord table = Arel::Table.new(table_name, engine) end - attribute = table[column.to_sym] + attribute = table[column] case value when ActiveRecord::Relation diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index 1cf9f00ad2..9069d9964f 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -3,7 +3,7 @@ module ActiveRecord MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 0de3786eb8..6c345cd8cc 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -188,6 +188,12 @@ module ActiveRecord assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"]) end + def test_raise_error_when_cannot_translate_exception + assert_raise TypeError do + @connection.send(:log, nil) { @connection.execute(nil) } + end + end + private def insert(ctx, data) binds = data.map { |name, value| diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index ee338a3b99..6556219205 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -11,8 +11,8 @@ if ActiveRecord::Base.connection.supports_migrations? def teardown @connection.drop_table :fruits rescue nil - @connection.drop_table :"_pre_fruits_suf_" rescue nil - @connection.drop_table :"_pre_schema_migrations_suf_" rescue nil + @connection.drop_table :"_p_fruits_s_" rescue nil + @connection.drop_table :"_p_schema_migrations_s_" rescue nil end def test_schema_define @@ -24,8 +24,9 @@ if ActiveRecord::Base.connection.supports_migrations? end def test_schema_define_with_table_prefix_and_suffix - ActiveRecord::Base.table_name_prefix = '_pre_' - ActiveRecord::Base.table_name_suffix = '_suf_' + # Use shorter prefix and suffix as in Oracle database identifier cannot be larger than 30 characters + ActiveRecord::Base.table_name_prefix = '_p_' + ActiveRecord::Base.table_name_suffix = '_s_' perform_schema_define! diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index f392366c19..c9b26895ae 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -14,6 +14,8 @@ require 'models/sponsor' require 'models/member' require 'models/essay' require 'models/toy' +require 'models/person' +require 'models/reader' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, @@ -716,4 +718,16 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal toy, sponsor.reload.sponsorable end + + def test_saving_nested_association + post1, post2 = Post.limit(2) + person = Person.new(:first_name => 'foo') + reader = Reader.new(:post => post1) + + reader.post_id = post2.id + person.readers = [reader] + + assert person.save + assert_equal reader.post_id, post2.id + end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 944f135153..42061d3d73 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -1118,4 +1118,11 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_no_queries { assert_equal 2, author.comments_with_order_and_conditions.size } assert_no_queries { assert_equal 5, author.posts.size, "should not cache a subset of the association" } end + + test "preloading a through association twice does not reset it" do + members = Member.includes(:current_membership => :club).includes(:club).to_a + assert_no_queries { + assert_equal 3, members.map(&:current_membership).map(&:club).size + } + end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 97d6c0cf88..67b5d174aa 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1540,6 +1540,16 @@ class BasicsTest < ActiveRecord::TestCase end end + def test_dont_clear_inheritnce_column_when_setting_explicitly + Joke.inheritance_column = "my_type" + before_inherit = Joke.inheritance_column + + Joke.reset_column_information + after_inherit = Joke.inheritance_column + + assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank? + end + def test_set_table_name_symbol_converted_to_string Joke.table_name = :cold_jokes assert_equal 'cold_jokes', Joke.table_name diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb index 3652255c38..32726e8d8b 100644 --- a/activerecord/test/cases/bind_parameter_test.rb +++ b/activerecord/test/cases/bind_parameter_test.rb @@ -30,8 +30,7 @@ module ActiveRecord end def test_binds_are_logged - # FIXME: use skip with minitest - return unless @connection.supports_statement_cache? + return skip_bind_parameter_test unless supports_statement_cache? sub = @connection.substitute_at(@pk, 0) binds = [[@pk, 1]] @@ -44,8 +43,7 @@ module ActiveRecord end def test_find_one_uses_binds - # FIXME: use skip with minitest - return unless @connection.supports_statement_cache? + return skip_bind_parameter_test unless supports_statement_cache? Topic.find(1) binds = [[@pk, 1]] @@ -54,8 +52,7 @@ module ActiveRecord end def test_logs_bind_vars - # FIXME: use skip with minitest - return unless @connection.supports_statement_cache? + return skip_bind_parameter_test unless supports_statement_cache? pk = Topic.columns.find { |x| x.primary } @@ -86,5 +83,15 @@ module ActiveRecord logger.sql event assert_match([[pk.name, 10]].inspect, logger.debugs.first) end + + private + + def skip_bind_parameter_test + skip('prepared statement caching is not supported') + end + + def supports_statement_cache? + @connection.supports_statement_cache? + end end end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 67137d168b..a1dc1de38d 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -493,6 +493,12 @@ class CalculationsTest < ActiveRecord::TestCase assert_equal [1,2,3,4], Topic.order(:id).pluck("topics.id") end + def test_pluck_replaces_select_clause + taks_relation = Topic.select([:approved, :id]).order(:id) + assert_equal [1,2,3,4], taks_relation.pluck(:id) + assert_equal [false, true, true, true], taks_relation.pluck(:approved) + end + def test_pluck_auto_table_name_prefix c = Company.create!(:name => "test", :contracts => [Contract.new]) assert_equal [c.id], Company.joins(:contracts).pluck(:id) diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 0ab4f30363..ac84306eae 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -212,14 +212,14 @@ class MethodScopingTest < ActiveRecord::TestCase table = VerySpecialComment.arel_table relation = VerySpecialComment.scoped relation.where_values << table[:id].not_eq(1) - assert_equal({:type => "VerySpecialComment"}, relation.send(:scope_for_create)) + assert_equal({'type' => "VerySpecialComment"}, relation.send(:scope_for_create)) end def test_scoped_create new_comment = nil VerySpecialComment.send(:with_scope, :create => { :post_id => 1 }) do - assert_equal({:post_id => 1, :type => 'VerySpecialComment' }, VerySpecialComment.scoped.send(:scope_for_create)) + assert_equal({'post_id' => 1, 'type' => 'VerySpecialComment' }, VerySpecialComment.scoped.send(:scope_for_create)) new_comment = VerySpecialComment.create :body => "Wonderful world" end @@ -228,7 +228,7 @@ class MethodScopingTest < ActiveRecord::TestCase def test_scoped_create_with_join_and_merge Comment.where(:body => "but Who's Buying?").joins(:post).merge(Post.where(:body => 'Peace Sells...')).with_scope do - assert_equal({:body => "but Who's Buying?"}, Comment.scoped.scope_for_create) + assert_equal({'body' => "but Who's Buying?"}, Comment.scoped.scope_for_create) end end @@ -441,7 +441,7 @@ class NestedScopingTest < ActiveRecord::TestCase comment = nil Comment.send(:with_scope, :create => { :post_id => 1}) do Comment.send(:with_scope, :create => { :post_id => 2}) do - assert_equal({:post_id => 2}, Comment.scoped.send(:scope_for_create)) + assert_equal({'post_id' => 2}, Comment.scoped.send(:scope_for_create)) comment = Comment.create :body => "Hey guys, nested scopes are broken. Please fix!" end end @@ -453,7 +453,7 @@ class NestedScopingTest < ActiveRecord::TestCase Comment.send(:with_scope, :create => { :body => "Hey guys, nested scopes are broken. Please fix!" }) do Comment.send(:with_exclusive_scope, :create => { :post_id => 1 }) do - assert_equal({:post_id => 1}, Comment.scoped.send(:scope_for_create)) + assert_equal({'post_id' => 1}, Comment.scoped.send(:scope_for_create)) assert_blank Comment.new.body comment = Comment.create :body => "Hey guys" end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 5b67d22c31..7f0d921545 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -61,7 +61,7 @@ if ActiveRecord::Base.connection.supports_migrations? ActiveRecord::Base.connection.initialize_schema_migrations_table ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}" - %w(things awesome_things prefix_things_suffix prefix_awesome_things_suffix).each do |table| + %w(things awesome_things prefix_things_suffix p_awesome_things_s).each do |table| Thing.connection.drop_table(table) rescue nil end Thing.reset_column_information @@ -874,8 +874,6 @@ if ActiveRecord::Base.connection.supports_migrations? end def test_remove_column_with_array_as_an_argument_is_deprecated - return skip "remove_column with array as argument is not supported with OracleAdapter" if current_adapter? :OracleAdapter - ActiveRecord::Base.connection.create_table(:hats) do |table| table.column :hat_name, :string, :limit => 100 table.column :hat_size, :integer @@ -886,7 +884,7 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.remove_column("hats", ["hat_name", "hat_size"]) end ensure - ActiveRecord::Base.connection.drop_table(:hats) rescue nil + ActiveRecord::Base.connection.drop_table(:hats) end def test_removing_and_renaming_column_preserves_custom_primary_key @@ -1647,8 +1645,8 @@ if ActiveRecord::Base.connection.supports_migrations? def test_rename_table_with_prefix_and_suffix assert !Thing.table_exists? - ActiveRecord::Base.table_name_prefix = 'prefix_' - ActiveRecord::Base.table_name_suffix = '_suffix' + ActiveRecord::Base.table_name_prefix = 'p_' + ActiveRecord::Base.table_name_suffix = '_s' Thing.reset_table_name Thing.reset_sequence_name WeNeedThings.up @@ -1657,7 +1655,7 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "hello world", Thing.find(:first).content RenameThings.up - Thing.table_name = "prefix_awesome_things_suffix" + Thing.table_name = "p_awesome_things_s" assert_equal "hello world", Thing.find(:first).content ensure diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 7a75a8436b..6efdeac3d9 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -71,7 +71,7 @@ module ActiveRecord def test_has_values relation = Relation.new Post, Post.arel_table relation.where_values << relation.table[:id].eq(10) - assert_equal({:id => 10}, relation.where_values_hash) + assert_equal({'id' => 10}, relation.where_values_hash) end def test_values_wrong_table @@ -101,7 +101,7 @@ module ActiveRecord def test_create_with_value relation = Relation.new Post, Post.arel_table - hash = { :hello => 'world' } + hash = { 'hello' => 'world' } relation.create_with_value = hash assert_equal hash, relation.scope_for_create end @@ -110,7 +110,7 @@ module ActiveRecord relation = Relation.new Post, Post.arel_table relation.where_values << relation.table[:id].eq(10) relation.create_with_value = {:hello => 'world'} - assert_equal({:hello => 'world', :id => 10}, relation.scope_for_create) + assert_equal({'hello' => 'world', 'id' => 10}, relation.scope_for_create) end # FIXME: is this really wanted or expected behavior? diff --git a/activeresource/CHANGELOG.md b/activeresource/CHANGELOG.md index 245b000f53..77419bb904 100644 --- a/activeresource/CHANGELOG.md +++ b/activeresource/CHANGELOG.md @@ -3,7 +3,7 @@ * No changes. -## Rails 3.2.13 (Feb 17, 2013) ## +## Rails 3.2.13 (Mar 18, 2013) ## * No changes. diff --git a/activeresource/lib/active_resource/version.rb b/activeresource/lib/active_resource/version.rb index 10b0e0858a..6c3ee00be6 100644 --- a/activeresource/lib/active_resource/version.rb +++ b/activeresource/lib/active_resource/version.rb @@ -3,7 +3,7 @@ module ActiveResource MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index ea72f692d3..649766cc9b 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,9 +1,12 @@ ## unreleased ## -* No changes. +* Fix `ActiveSupport::TimeZone.parse` when time is at a local DST jump. + Fixes #9678. + + *Andrew White* -## Rails 3.2.13 (Feb 17, 2013) ## +## Rails 3.2.13 (Mar 18, 2013) ## * Fix DateTime comparison with DateTime::Infinity object. diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index cbe0947a8a..fb3575b865 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -18,6 +18,6 @@ Gem::Specification.new do |s| s.rdoc_options.concat ['--encoding', 'UTF-8'] - s.add_dependency('i18n', '= 0.6.1') + s.add_dependency('i18n', '~> 0.6', '>= 0.6.4') s.add_dependency('multi_json', '~> 1.0') end diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index c7d8fc2e17..f935180036 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -268,13 +268,23 @@ module ActiveSupport # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00 # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00 def parse(str, now=now) - date_parts = Date._parse(str) - return if date_parts.blank? - time = Time.parse(str, now) rescue DateTime.parse(str) - if date_parts[:offset].nil? - ActiveSupport::TimeWithZone.new(nil, self, time) + parts = Date._parse(str, false) + return if parts.empty? + + time = Time.utc( + parts.fetch(:year, now.year), + parts.fetch(:mon, now.month), + parts.fetch(:mday, now.day), + parts.fetch(:hour, 0), + parts.fetch(:min, 0), + parts.fetch(:sec, 0), + parts.fetch(:sec_fraction, 0) * 1000000 + ) + + if parts[:offset] + TimeWithZone.new(time - parts[:offset], self) else - time.in_time_zone(self) + TimeWithZone.new(nil, self, time) end end diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index ce6a47f110..03b1e511d9 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -3,7 +3,7 @@ module ActiveSupport MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb index 6c222b83ba..8d23ce4e18 100644 --- a/activesupport/lib/active_support/xml_mini/jdom.rb +++ b/activesupport/lib/active_support/xml_mini/jdom.rb @@ -38,6 +38,12 @@ module ActiveSupport {} else @dbf = DocumentBuilderFactory.new_instance + # secure processing of java xml + # http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html + @dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false) + @dbf.setFeature("http://xml.org/sax/features/external-general-entities", false) + @dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false) + @dbf.setFeature(javax.xml.XMLConstants::FEATURE_SECURE_PROCESSING, true) xml_string_reader = StringReader.new(data) xml_input_source = InputSource.new(xml_string_reader) doc = @dbf.new_document_builder.parse(xml_input_source) diff --git a/activesupport/test/fixtures/xml/jdom_doctype.dtd b/activesupport/test/fixtures/xml/jdom_doctype.dtd new file mode 100644 index 0000000000..89480496ef --- /dev/null +++ b/activesupport/test/fixtures/xml/jdom_doctype.dtd @@ -0,0 +1 @@ +<!ENTITY a "external entity"> diff --git a/activesupport/test/fixtures/xml/jdom_entities.txt b/activesupport/test/fixtures/xml/jdom_entities.txt new file mode 100644 index 0000000000..0337fdaa08 --- /dev/null +++ b/activesupport/test/fixtures/xml/jdom_entities.txt @@ -0,0 +1 @@ +<!ENTITY a "hello"> diff --git a/activesupport/test/fixtures/xml/jdom_include.txt b/activesupport/test/fixtures/xml/jdom_include.txt new file mode 100644 index 0000000000..239ca3afaf --- /dev/null +++ b/activesupport/test/fixtures/xml/jdom_include.txt @@ -0,0 +1 @@ +include me diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index 8ecfc1e47e..bd4bfca82c 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -198,6 +198,62 @@ class TimeZoneTest < Test::Unit::TestCase assert_equal Time.utc(1999,12,31,19), twz.time end + def test_parse_should_not_black_out_system_timezone_dst_jump + with_env_tz('EET') do + zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] + twz = zone.parse('2012-03-25 03:29:00') + assert_equal [0, 29, 3, 25, 3, 2012], twz.to_a[0,6] + end + end + + def test_parse_should_black_out_app_timezone_dst_jump + with_env_tz('EET') do + zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)'] + twz = zone.parse('2012-03-11 02:29:00') + assert_equal [0, 29, 3, 11, 3, 2012], twz.to_a[0,6] + end + end + + def test_parse_with_javascript_date + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + twz = zone.parse("Mon May 28 2012 00:00:00 GMT-0700 (PDT)") + assert_equal Time.utc(2012, 5, 28, 7, 0, 0), twz.utc + end + + def test_parse_with_missing_time_components + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + zone.stubs(:now).returns zone.local(1999, 12, 31, 12, 59, 59) + twz = zone.parse('2012-12-01') + assert_equal Time.utc(2012, 12, 1), twz.time + end + + def test_parse_doesnt_use_local_dst + with_env_tz 'US/Eastern' do + zone = ActiveSupport::TimeZone['UTC'] + twz = zone.parse('2013-03-10 02:00:00') + assert_equal Time.utc(2013, 3, 10, 2, 0, 0), twz.time + end + end + + def test_parse_handles_dst_jump + with_env_tz 'US/Eastern' do + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + twz = zone.parse('2013-03-10 02:00:00') + assert_equal Time.utc(2013, 3, 10, 3, 0, 0), twz.time + end + end + + def test_parse_with_fractional_seconds + zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] + twz = zone.parse('2013-03-13 00:00:00.000001') + assert_equal 1, twz.usec + + if twz.respond_to?(:nsec) + twz = zone.parse('2013-03-13 00:00:00.000000001') + assert_equal 1, twz.nsec + end + end + def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize tzinfo = TZInfo::Timezone.get('America/New_York') zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo) diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb index 7f809e7898..dfe2c417ca 100644 --- a/activesupport/test/xml_mini/jdom_engine_test.rb +++ b/activesupport/test/xml_mini/jdom_engine_test.rb @@ -3,9 +3,11 @@ if RUBY_PLATFORM =~ /java/ require 'active_support/xml_mini' require 'active_support/core_ext/hash/conversions' - class JDOMEngineTest < Test::Unit::TestCase + class JDOMEngineTest < ActiveSupport::TestCase include ActiveSupport + FILES_DIR = File.dirname(__FILE__) + '/../fixtures/xml' + def setup @default_backend = XmlMini.backend XmlMini.backend = 'JDOM' @@ -30,10 +32,41 @@ if RUBY_PLATFORM =~ /java/ assert_equal 'image/png', file.content_type end + def test_not_allowed_to_expand_entities_to_files + attack_xml = <<-EOT + <!DOCTYPE member [ + <!ENTITY a SYSTEM "file://#{FILES_DIR}/jdom_include.txt"> + ]> + <member>x&a;</member> + EOT + assert_equal 'x', Hash.from_xml(attack_xml)["member"] + end + + def test_not_allowed_to_expand_parameter_entities_to_files + attack_xml = <<-EOT + <!DOCTYPE member [ + <!ENTITY % b SYSTEM "file://#{FILES_DIR}/jdom_entities.txt"> + %b; + ]> + <member>x&a;</member> + EOT + assert_raise Java::OrgXmlSax::SAXParseException do + assert_equal 'x', Hash.from_xml(attack_xml)["member"] + end + end + + + def test_not_allowed_to_load_external_doctypes + attack_xml = <<-EOT + <!DOCTYPE member SYSTEM "file://#{FILES_DIR}/jdom_doctype.dtd"> + <member>x&a;</member> + EOT + assert_equal 'x', Hash.from_xml(attack_xml)["member"] + end + def test_exception_thrown_on_expansion_attack - assert_raise NativeException do + assert_raise Java::OrgXmlSax::SAXParseException do attack_xml = <<-EOT - <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE member [ <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;"> <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;"> diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 8064b0b5cc..c0ab4b8317 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -3,7 +3,7 @@ * No changes. -## Rails 3.2.13 (Feb 17, 2013) ## +## Rails 3.2.13 (Mar 18, 2013) ## * No changes. diff --git a/railties/guides/source/action_mailer_basics.textile b/railties/guides/source/action_mailer_basics.textile index 26c95be031..73f4ce3695 100644 --- a/railties/guides/source/action_mailer_basics.textile +++ b/railties/guides/source/action_mailer_basics.textile @@ -480,7 +480,7 @@ As Action Mailer now uses the Mail gem, this becomes as simple as adding to your <ruby> config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { - :address => "smtp.gmail.com", + :address => 'smtp.gmail.com', :port => 587, :domain => 'baci.lindsaar.net', :user_name => '<username>', diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 0e811a2527..c2ca5a335d 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -86,9 +86,9 @@ Or, you can set custom gzip compression level (level names are taken from +Zlib+ caches_page :image, :gzip => :best_speed </ruby> -NOTE: Page caching ignores all parameters. For example +/products?page=1+ will be written out to the filesystem as +products.html+ with no reference to the +page+ parameter. Thus, if someone requests +/products?page=2+ later, they will get the cached first page. A workaround for this limitation is to include the parameters in the page's path, e.g. +/productions/page/1+. +NOTE: Page caching ignores all parameters. For example +/products?page=1+ will be written out to the filesystem as +products.html+ with no reference to the +page+ parameter. Thus, if someone requests +/products?page=2+ later, they will get the cached first page. A workaround for this limitation is to include the parameters in the products's path, e.g. +/products/page/1+. -INFO: Page caching runs in an after filter. Thus, invalid requests won't generate spurious cache entries as long as you halt them. Typically, a redirection in some before filter that checks request preconditions does the job. +INFO: Page caching runs as an after filter. Thus, invalid requests won't generate spurious cache entries as long as you halt them. Typically, a redirection in some before filter that checks request preconditions does the job. h4. Action Caching diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile index c32a23c50b..99409edbd0 100644 --- a/railties/guides/source/getting_started.textile +++ b/railties/guides/source/getting_started.textile @@ -1153,6 +1153,7 @@ First, take a look at +comment.rb+: <ruby> class Comment < ActiveRecord::Base + attr_accesssible :body, :commenter, :post belongs_to :post end </ruby> @@ -1215,6 +1216,7 @@ makes each comment belong to a Post: <ruby> class Comment < ActiveRecord::Base + attr_accessible :body, :commenter, :post belongs_to :post end </ruby> diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 854ac2cbbc..4f695159ea 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -167,7 +167,7 @@ module Rails # These parameters will be used by middlewares and engines to configure themselves. # def env_config - @env_config ||= super.merge({ + @app_env_config ||= super.merge({ "action_dispatch.parameter_filter" => config.filter_parameters, "action_dispatch.secret_token" => config.secret_token, "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index 4be683e499..0145879c87 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -3,7 +3,7 @@ module Rails MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index ab9084df55..107b54c0be 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -122,6 +122,18 @@ module ApplicationTests assert_equal 0, ::AppTemplate::Application::User.count end + def test_loading_only_yml_fixtures + Dir.chdir(app_path) do + `rake db:migrate` + end + + app_file "test/fixtures/products.csv", "" + + require "#{rails_root}/config/environment" + errormsg = Dir.chdir(app_path) { `rake db:fixtures:load` } + assert $?.success?, errormsg + end + def test_scaffold_tests_pass_by_default content = Dir.chdir(app_path) do `rails generate scaffold user username:string password:string` diff --git a/version.rb b/version.rb index 4be683e499..0145879c87 100644 --- a/version.rb +++ b/version.rb @@ -3,7 +3,7 @@ module Rails MAJOR = 3 MINOR = 2 TINY = 13 - PRE = "rc2" + PRE = nil STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end |