aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md7
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb5
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb13
-rw-r--r--actionview/CHANGELOG.md4
-rw-r--r--actionview/test/template/erb_util_test.rb1
-rw-r--r--actionview/test/template/tag_helper_test.rb1
-rw-r--r--activemodel/lib/active_model/secure_password.rb2
-rw-r--r--activemodel/test/cases/secure_password_test.rb13
-rw-r--r--activemodel/test/models/user.rb1
-rw-r--r--activemodel/test/models/visitor.rb1
-rw-r--r--activerecord/lib/active_record/attribute_set.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/core.rb5
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb11
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb17
-rw-r--r--activesupport/CHANGELOG.md7
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb2
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb1
21 files changed, 89 insertions, 23 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index cc72aa3081..c8ea4052f6 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,10 @@
+* JSONP responses are now rendered with the `text/javascript` content type
+ when rendering through a `respond_to` block.
+
+ Fixes #15081.
+
+ *Lucas Mazza*
+
* Add `config.action_controller.always_permitted_parameters` to configure which
parameters are permitted globally. The default value of this configuration is
`['controller', 'action']`.
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 46405cef55..ae55e6d7f5 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -112,7 +112,10 @@ module ActionController
json = json.to_json(options) unless json.kind_of?(String)
if options[:callback].present?
- self.content_type ||= Mime::JS
+ if self.content_type.nil? || self.content_type == Mime::JSON
+ self.content_type = Mime::JS
+ end
+
"#{options[:callback]}(#{json})"
else
self.content_type ||= Mime::JSON
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index 41503e11a8..c89b95de3b 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -128,6 +128,12 @@ class RespondToController < ActionController::Base
end
end
+ def json_with_callback
+ respond_to do |type|
+ type.json { render :json => 'JS', :callback => 'alert' }
+ end
+ end
+
def iphone_with_html_response_type
request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone"
@@ -511,6 +517,13 @@ class RespondToControllerTest < ActionController::TestCase
assert_equal '<html><div id="html">HTML for all_types_with_layout</div></html>', @response.body
end
+ def test_json_with_callback_sets_javascript_content_type
+ @request.accept = 'application/json'
+ get :json_with_callback
+ assert_equal 'alert(JS)', @response.body
+ assert_equal 'text/javascript', @response.content_type
+ end
+
def test_xhr
xhr :get, :js_or_html
assert_equal 'JS', @response.body
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 755c817a98..185f420472 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Fix `html_escape_once` to properly handle hex escape sequences (e.g. &#x1a2b;)
+
+ *John F. Douthat*
+
* Added String support for min and max properties for date field helpers.
*Todd Bealmear*
diff --git a/actionview/test/template/erb_util_test.rb b/actionview/test/template/erb_util_test.rb
index 9bacbba908..3bb84cbc50 100644
--- a/actionview/test/template/erb_util_test.rb
+++ b/actionview/test/template/erb_util_test.rb
@@ -92,6 +92,7 @@ class ErbUtilTest < ActiveSupport::TestCase
def test_html_escape_once
assert_equal '1 &lt;&gt;&amp;&quot;&#39; 2 &amp; 3', html_escape_once('1 <>&"\' 2 &amp; 3')
+ assert_equal " &#X27; &#x27; &#x03BB; &#X03bb; &quot; &#39; &lt; &gt; ", html_escape_once(" &#X27; &#x27; &#x03BB; &#X03bb; \" ' < > ")
end
def test_html_escape_once_returns_unsafe_strings_when_passed_unsafe_strings
diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb
index c78b6450f2..0ea669b3d0 100644
--- a/actionview/test/template/tag_helper_test.rb
+++ b/actionview/test/template/tag_helper_test.rb
@@ -123,6 +123,7 @@ class TagHelperTest < ActionView::TestCase
def test_escape_once
assert_equal '1 &lt; 2 &amp; 3', escape_once('1 < 2 &amp; 3')
+ assert_equal " &#X27; &#x27; &#x03BB; &#X03bb; &quot; &#39; &lt; &gt; ", escape_once(" &#X27; &#x27; &#x03BB; &#X03bb; \" ' < > ")
end
def test_tag_honors_html_safe_for_param_values
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index fdfd8cb147..7e179cf4b7 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -64,6 +64,8 @@ module ActiveModel
include InstanceMethodsOnActivation
if options.fetch(:validations, true)
+ include ActiveModel::Validations
+
# This ensures the model has a password by checking whether the password_digest
# is present, so that this works with both new and existing records. However,
# when there is an error, the message is added to the password attribute instead
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index e59f00c8c5..6b21bc68fa 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -20,15 +20,12 @@ class SecurePasswordTest < ActiveModel::TestCase
ActiveModel::SecurePassword.min_cost = @original_min_cost
end
- test "create/update without validations" do
- assert @visitor.valid?(:create), 'visitor should be valid'
- assert @visitor.valid?(:update), 'visitor should be valid'
-
- @visitor.password = '123'
- @visitor.password_confirmation = '456'
+ test "automatically include ActiveModel::Validations when validations are enabled" do
+ assert_respond_to @user, :valid?
+ end
- assert @visitor.valid?(:create), 'visitor should be valid'
- assert @visitor.valid?(:update), 'visitor should be valid'
+ test "don't include ActiveModel::Validations when validations are disabled" do
+ assert_not_respond_to @visitor, :valid?
end
test "create a new user with validations and valid password/confirmation" do
diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb
index cbe259b1ad..1ec6001c48 100644
--- a/activemodel/test/models/user.rb
+++ b/activemodel/test/models/user.rb
@@ -1,6 +1,5 @@
class User
extend ActiveModel::Callbacks
- include ActiveModel::Validations
include ActiveModel::SecurePassword
define_model_callbacks :create
diff --git a/activemodel/test/models/visitor.rb b/activemodel/test/models/visitor.rb
index 4d7f4be097..22ad1a3c3d 100644
--- a/activemodel/test/models/visitor.rb
+++ b/activemodel/test/models/visitor.rb
@@ -1,6 +1,5 @@
class Visitor
extend ActiveModel::Callbacks
- include ActiveModel::Validations
include ActiveModel::SecurePassword
define_model_callbacks :create
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index df4fd31e08..64df6f6358 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -58,6 +58,12 @@ module ActiveRecord
end
end
+ def ensure_initialized(key)
+ unless self[key].initialized?
+ write_from_database(key, nil)
+ end
+ end
+
protected
attr_reader :attributes
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index f9541b437a..60b0ee526e 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -23,7 +23,8 @@ module ActiveRecord
case value
when Range
if /range$/ =~ sql_type
- "'#{PostgreSQLColumn.range_to_string(value)}'::#{sql_type}"
+ escaped = quote_string(PostgreSQLColumn.range_to_string(value))
+ "'#{escaped}'::#{sql_type}"
else
super
end
@@ -52,8 +53,8 @@ module ActiveRecord
when 'xml' then "xml '#{quote_string(value)}'"
when /^bit/
case value
- when /^[01]*$/ then "B'#{value}'" # Bit-string notation
- when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
+ when /\A[01]*\Z/ then "B'#{value}'" # Bit-string notation
+ when /\A[0-9A-F]*\Z/i then "X'#{value}'" # Hexadecimal notation
end
else
super
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index a164758640..8e31e165b1 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -569,7 +569,7 @@ module ActiveRecord
end
def exec_no_cache(sql, name, binds)
- log(sql, name, binds) { @connection.async_exec(sql) }
+ log(sql, name, binds) { @connection.async_exec(sql, []) }
end
def exec_cache(sql, name, binds)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 30b8485c8b..b11c4f804f 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -514,10 +514,7 @@ module ActiveRecord
end
def init_internals
- pk = self.class.primary_key
- if pk && !@attributes.include?(pk)
- @attributes.write_from_database(pk, nil)
- end
+ @attributes.ensure_initialized(self.class.primary_key)
@aggregation_cache = {}
@association_cache = {}
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index b4ae204813..90e99957f6 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -34,7 +34,7 @@ module ActiveRecord
# # => counts the number of different age values
#
# Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
- # between databases. In invalid cases, an error from the databsae is thrown.
+ # between databases. In invalid cases, an error from the database is thrown.
def count(column_name = nil, options = {})
# TODO: Remove options argument as soon we remove support to
# activerecord-deprecated_finders.
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index 218c59247e..6f00c0d333 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -57,6 +57,17 @@ module ActiveRecord
assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0))
assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0).to_datetime)
end
+
+ def test_quote_range
+ range = "1,2]'; SELECT * FROM users; --".."a"
+ c = PostgreSQLColumn.new(nil, nil, OID::Range.new(Type::Integer.new, :int8range))
+ assert_equal "'[1,2]''; SELECT * FROM users; --,a]'::int8range", @conn.quote(range, c)
+ end
+
+ def test_quote_bit_string
+ c = PostgreSQLColumn.new(nil, 1, OID::Bit.new)
+ assert_equal nil, @conn.quote("'); SELECT * FORM users; /*\n01\n*/--", c)
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
index 0f6e39322c..02d0a9b483 100644
--- a/activerecord/test/cases/adapters/postgresql/range_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -262,6 +262,23 @@ _SQL
assert_raises(ArgumentError) { PostgresqlRange.create!(float_range: "(0.5, 0.7]") }
end
+ def test_update_all_with_ranges
+ PostgresqlRange.create!
+
+ PostgresqlRange.update_all(int8_range: 1..100)
+
+ assert_equal 1...101, PostgresqlRange.first.int8_range
+ end
+
+ def test_ranges_correctly_escape_input
+ e = assert_raises(ActiveRecord::StatementInvalid) do
+ range = "1,2]'; SELECT * FROM users; --".."a"
+ PostgresqlRange.update_all(int8_range: range)
+ end
+
+ assert e.message.starts_with?("PG::InvalidTextRepresentation")
+ end
+
private
def assert_equal_round_trip(range, attribute, value)
round_trip(range, attribute, value)
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index efaa6cd2a3..005bcffa26 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,10 @@
+* `DateTime#to_f` now preserves the fractional seconds instead of always
+ rounding to `.0`.
+
+ Fixes #15994.
+
+ *John Paul Ashenfelter*
+
* Add `Hash#transform_values` to simplify a common pattern where the values of a
hash must change, but the keys are left the same.
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index 6ddfb72a0d..2a9c09fc29 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -71,9 +71,9 @@ class DateTime
civil(year, month, day, hour, min, sec, offset)
end
- # Converts +self+ to a floating-point number of seconds since the Unix epoch.
+ # Converts +self+ to a floating-point number of seconds, including fractional microseconds, since the Unix epoch.
def to_f
- seconds_since_unix_epoch.to_f
+ seconds_since_unix_epoch.to_f + sec_fraction
end
# Converts +self+ to an integer number of seconds since the Unix epoch.
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 46cd170c1d..c761325108 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -7,7 +7,7 @@ class ERB
HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003e', '<' => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
HTML_ESCAPE_REGEXP = /[&"'><]/
- HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
# A utility method for escaping HTML tag characters.
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index 2c08b46791..74319ecd09 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -338,6 +338,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
def test_to_f
assert_equal 946684800.0, DateTime.civil(2000).to_f
assert_equal 946684800.0, DateTime.civil(1999,12,31,19,0,0,Rational(-5,24)).to_f
+ assert_equal 946684800.5, DateTime.civil(1999,12,31,19,0,0.5,Rational(-5,24)).to_f
end
def test_to_i