diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 458f4045e46ca..91008bce49aa9 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,3 +1,7 @@ +* Make `ActiveModel::Serializers::JSON#from_json` compatible with `#assign_attributes` + + *Sean Doyle* + * Fix a bug where type casting of string to `Time` and `DateTime` doesn't calculate minus minute value in TZ offset correctly. diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb index c6cff11e5ecb4..2879eb2258504 100644 --- a/activemodel/lib/active_model/serializers/json.rb +++ b/activemodel/lib/active_model/serializers/json.rb @@ -146,7 +146,13 @@ def as_json(options = nil) def from_json(json, include_root = include_root_in_json) hash = ActiveSupport::JSON.decode(json) hash = hash.values.first if include_root - self.attributes = hash + + if respond_to?(:assign_attributes) + assign_attributes(hash) + else + self.attributes = hash + end + self end end diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb index 050fef1182dca..25e008240ba28 100644 --- a/activemodel/test/cases/serializers/json_serialization_test.rb +++ b/activemodel/test/cases/serializers/json_serialization_test.rb @@ -5,6 +5,14 @@ require "active_support/core_ext/object/instance_variables" class JsonSerializationTest < ActiveModel::TestCase + class CamelContact < Contact + include ActiveModel::AttributeAssignment + + def assign_attributes(attributes) + super(attributes.deep_transform_keys(&:underscore)) + end + end + def setup @contact = Contact.new @contact.name = "Konata Izumi" @@ -178,6 +186,18 @@ def @contact.favorite_quote; "Constraints are liberating"; end assert_equal result.preferences, @contact.preferences end + test "from_json supports models that include ActiveModel::AttributeAssignment and override assign_attributes" do + serialized = @contact.as_json + serialized.deep_transform_keys! { |key| key.camelize(:lower) } + result = CamelContact.new.from_json(serialized.to_json) + + assert_equal result.name, @contact.name + assert_equal result.age, @contact.age + assert_equal Time.parse(result.created_at), @contact.created_at + assert_equal result.awesome, @contact.awesome + assert_equal result.preferences, @contact.preferences + end + test "custom as_json should be honored when generating json" do def @contact.as_json(options = nil); { name: name, created_at: created_at }; end json = @contact.to_json