diff --git a/CHANGES.md b/CHANGES.md index cf01881..fa499b9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ # Changes +## 1.22.2 + +- fix instantiating properties that include CouchPotato::Persistence (call .json_create instead of .new) ## 1.22.1 diff --git a/lib/couch_potato/persistence/simple_property.rb b/lib/couch_potato/persistence/simple_property.rb index 8bcf16d..2c3206b 100644 --- a/lib/couch_potato/persistence/simple_property.rb +++ b/lib/couch_potato/persistence/simple_property.rb @@ -13,9 +13,9 @@ def load_attribute_from_document(name) end end - def assign_attribute(name, value) + def assign_attribute(name, value, from_json: false) property = self.class.properties.find_property(name) - typecasted_value = type_caster.cast(value, property.type) + typecasted_value = type_caster.cast(value, property.type, from_json:) send("#{name}_will_change!") unless @skip_dirty_tracking || typecasted_value == send(name) instance_variable_set("@#{name}", typecasted_value) end @@ -35,7 +35,7 @@ def initialize(owner_clazz, name, options = {}) end def build(object, json) - object.send(:assign_attribute, name, json[name]) + object.send(:assign_attribute, name, json[name], from_json: true) end def serialize(json, object) diff --git a/lib/couch_potato/persistence/type_caster.rb b/lib/couch_potato/persistence/type_caster.rb index cff3aa1..eb01bb0 100644 --- a/lib/couch_potato/persistence/type_caster.rb +++ b/lib/couch_potato/persistence/type_caster.rb @@ -6,14 +6,14 @@ module Persistence class TypeCaster #:nodoc: NUMBER_REGEX = /-?\d*\.?\d*/.freeze - def cast(value, type) + def cast(value, type, from_json: false) if type == :boolean cast_boolean(value) elsif type.instance_of?(Array) nested_type = type.first - value&.map { |val| cast_native(val, nested_type) } + value&.map { |val| cast_native(val, nested_type, from_json:) } else - cast_native(value, type) + cast_native(value, type, from_json:) end end @@ -29,7 +29,7 @@ def cast_boolean(value) end end - def cast_native(value, type) + def cast_native(value, type, from_json:) if type && !value.is_a?(type) if %w[Integer Bignum].include?(type.to_s) @@ -40,7 +40,7 @@ def cast_native(value, type) value.to_d unless value.blank? elsif type == Hash value.to_hash unless value.blank? - elsif type.ancestors.include?(CouchPotato::Persistence) + elsif type.ancestors.include?(CouchPotato::Persistence) && !from_json type.new value unless value.blank? else type.json_create value unless value.blank? diff --git a/lib/couch_potato/version.rb b/lib/couch_potato/version.rb index dbe05d9..9665c10 100644 --- a/lib/couch_potato/version.rb +++ b/lib/couch_potato/version.rb @@ -1,4 +1,4 @@ module CouchPotato - VERSION = '1.22.1'.freeze + VERSION = '1.22.2'.freeze RSPEC_VERSION = '4.4.0'.freeze end diff --git a/spec/property_spec.rb b/spec/property_spec.rb index 62a91cb..cd8828d 100644 --- a/spec/property_spec.rb +++ b/spec/property_spec.rb @@ -132,8 +132,8 @@ class SportsWatch < Watch expect(w.custom_address[0]).to be_an_instance_of Address2 end - it 'initializes an typed array property from an array of hashes' do - w = Watch.new(custom_address: [{id: 'a1', city: 'Berlin'}]) + it 'initializes a typed array property from an array of hashes' do + w = Watch.new(custom_address: [{_id: 'a1', city: 'Berlin'}]) expect(w.custom_address.map(&:class)).to eq([Address]) expect(w.custom_address.map(&:id)).to eq(['a1']) @@ -198,6 +198,32 @@ def it_should_persist value expect(p.ship_address).to be_nil end + it "persists a nested object with non-couch potato attributes delegating to properties" do + class PersonWithName + include CouchPotato::Persistence + + property :first_name + property :last_name + + def name=(value) + self.first_name = value.split(' ').first + self.last_name = value.split(' ').last + end + end + class PersonContainer + include CouchPotato::Persistence + + property :person, type: PersonWithName + end + + container = PersonContainer.new(person: {name: 'John Doe'}) + CouchPotato.database.save_document!(container) + container = CouchPotato.database.load_document(container.id) + + expect(container.person.first_name).to eq('John') + expect(container.person.last_name).to eq('Doe') + end + it "should actually pass the null value down in the JSON document " do p = Person.new p.ship_address = nil