提交 a0309775 编写于 作者: G Godfrey Chan

Merge pull request #16059 from jenncoop/json-serialized-attr

Fixed issue with ActiveRecord serialize object as JSON

Conflicts:
	activerecord/CHANGELOG.md
	activerecord/lib/active_record/attribute_methods/serialization.rb
上级 acec038b
* Restore 4.0 behavior for using serialize attributes with `JSON` as coder.
With 4.1.x, `serialize` started returning a string when `JSON` was passed as
the second attribute. It will now return a hash as per previous versions.
Example:
class Post < ActiveRecord::Base
serialize :comment, JSON
end
class Comment
include ActiveModel::Model
attr_accessor :category, :text
end
post = Post.create!
post.comment = Comment.new(category: "Animals", text: "This is a comment about squirrels.")
post.save!
# 4.0
post.comment # => {"category"=>"Animals", "text"=>"This is a comment about squirrels."}
# 4.1 before
post.comment # => "#<Comment:0x007f80ab48ff98>"
# 4.1 after
post.comment # => {"category"=>"Animals", "text"=>"This is a comment about squirrels."}
When using `JSON` as the coder in `serialize`, Active Record will use the
new `ActiveRecord::Coders::JSON` coder which delegates its `dump/load` to
`ActiveSupport::JSON.encode/decode`. This ensures special objects are dumped
correctly using the `#as_json` hook.
To keep the previous behaviour, supply a custom coder instead
([example](https://gist.github.com/jenncoop/8c4142bbe59da77daa63)).
Fixes #15594.
*Jenn Cooper*
* Add a `:required` option to singular associations, providing a nicer
API for presence validations on associations.
......
......@@ -97,6 +97,7 @@ module ActiveRecord
module Coders
autoload :YAMLColumn, 'active_record/coders/yaml_column'
autoload :JSON, 'active_record/coders/json'
end
module AttributeMethods
......
......@@ -37,7 +37,12 @@ module ClassMethods
# serialize :preferences, Hash
# end
def serialize(attr_name, class_name_or_coder = Object)
coder = if [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
# When ::JSON is used, force it to go through the Active Support JSON encoder
# to ensure special objects (e.g. Active Record models) are dumped correctly
# using the #as_json hook.
coder = if class_name_or_coder == ::JSON
Coders::JSON
elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
class_name_or_coder
else
Coders::YAMLColumn.new(class_name_or_coder)
......
module ActiveRecord
module Coders # :nodoc:
class JSON # :nodoc:
def self.dump(obj)
ActiveSupport::JSON.encode(obj)
end
def self.load(json)
ActiveSupport::JSON.decode(json)
end
end
end
end
......@@ -3,10 +3,11 @@
require 'models/reply'
require 'models/person'
require 'models/traffic_light'
require 'models/post'
require 'bcrypt'
class SerializedAttributeTest < ActiveRecord::TestCase
fixtures :topics
fixtures :topics, :posts
MyObject = Struct.new :attribute1, :attribute2
......@@ -67,6 +68,19 @@ def test_serialized_attribute_calling_dup_method
assert_equal(orig.content, clone.content)
end
def test_serialized_json_attribute_returns_unserialized_value
Topic.serialize :content, JSON
my_post = posts(:welcome)
t = Topic.new(content: my_post)
t.save!
t.reload
assert_instance_of(Hash, t.content)
assert_equal(my_post.id, t.content["id"])
assert_equal(my_post.title, t.content["title"])
end
def test_serialized_attribute_declared_in_subclass
hash = { 'important1' => 'value1', 'important2' => 'value2' }
important_topic = ImportantTopic.create("important" => hash)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册