Properly serialize all JSON primitives in the AR JSON type

Previously we were assuming that the only valid types for encoding were
arrays and hashes. However, any JSON primitive is an accepted value by
both PG and MySQL.

This does involve a minor breaking change in the handling of `default`
in the schema dumper. This is easily worked around, as passing a
hash/array literal would have worked fine in previous versions of Rails.
However, because of this, I will not be backporting this to 4.2 or
earlier.

Fixes #24234
This commit is contained in:
Sean Griffin 2016-04-13 10:48:11 -06:00
parent 2b92069a49
commit efaa6e4f79
4 changed files with 30 additions and 14 deletions

View File

@ -1,3 +1,9 @@
* Properly accept all valid JSON primitives in the JSON data type.
Fixes #24234
*Sean Griffin*
* MariaDB 5.3+ supports microsecond datetime precision.
*Jeremy Daer*

View File

@ -17,11 +17,7 @@ module ActiveRecord
end
def serialize(value)
if value.is_a?(::Array) || value.is_a?(::Hash)
::ActiveSupport::JSON.encode(value)
else
value
end
::ActiveSupport::JSON.encode(value)
end
def accessor

View File

@ -161,12 +161,19 @@ class Mysql2JSONTest < ActiveRecord::Mysql2TestCase
assert_not json.changed?
end
def test_assigning_invalid_json
json = JsonDataType.new
def test_assigning_string_literal
json = JsonDataType.create(payload: "foo")
assert_equal "foo", json.payload
end
json.payload = 'foo'
def test_assigning_number
json = JsonDataType.create(payload: 1.234)
assert_equal 1.234, json.payload
end
assert_nil json.payload
def test_assigning_boolean
json = JsonDataType.create(payload: true)
assert_equal true, json.payload
end
end
end

View File

@ -38,7 +38,7 @@ module PostgresqlJSONSharedTestCases
end
def test_default
@connection.add_column 'json_data_type', 'permissions', column_type, default: '{"users": "read", "posts": ["read", "write"]}'
@connection.add_column 'json_data_type', 'permissions', column_type, default: {"users": "read", "posts": ["read", "write"]}
JsonDataType.reset_column_information
assert_equal({"users"=>"read", "posts"=>["read", "write"]}, JsonDataType.column_defaults['permissions'])
@ -178,12 +178,19 @@ module PostgresqlJSONSharedTestCases
assert_not json.changed?
end
def test_assigning_invalid_json
json = JsonDataType.new
def test_assigning_string_literal
json = JsonDataType.create(payload: "foo")
assert_equal "foo", json.payload
end
json.payload = 'foo'
def test_assigning_number
json = JsonDataType.create(payload: 1.234)
assert_equal 1.234, json.payload
end
assert_nil json.payload
def test_assigning_boolean
json = JsonDataType.create(payload: true)
assert_equal true, json.payload
end
end