lib/lockbox/model.rb in lockbox-0.6.2 vs lib/lockbox/model.rb in lockbox-0.6.3

- old
+ new

@@ -192,12 +192,15 @@ # same logic as Active Record # (although this happens before saving) attributes_to_set.each do |k, v| if respond_to?(:write_attribute_without_type_cast, true) write_attribute_without_type_cast(k, v) - else + elsif respond_to?(:raw_write_attribute, true) raw_write_attribute(k, v) + else + @attributes.write_cast_value(k, v) + clear_attribute_change(k) end end result end @@ -252,11 +255,16 @@ # hack for Active Record 6.1 # to set string type after serialize # otherwise, type gets set to ActiveModel::Type::Value # which always returns false for changed_in_place? # earlier versions of Active Record take the previous code path - if ActiveRecord::VERSION::STRING.to_f >= 6.1 && attributes_to_define_after_schema_loads[name.to_s].first.is_a?(Proc) + if ActiveRecord::VERSION::STRING.to_f >= 7.0 && attributes_to_define_after_schema_loads[name.to_s].first.is_a?(Proc) + attribute_type = attributes_to_define_after_schema_loads[name.to_s].first.call(nil) + if attribute_type.is_a?(ActiveRecord::Type::Serialized) && attribute_type.subtype.nil? + attribute name, ActiveRecord::Type::Serialized.new(ActiveRecord::Type::String.new, attribute_type.coder) + end + elsif ActiveRecord::VERSION::STRING.to_f >= 6.1 && attributes_to_define_after_schema_loads[name.to_s].first.is_a?(Proc) attribute_type = attributes_to_define_after_schema_loads[name.to_s].first.call if attribute_type.is_a?(ActiveRecord::Type::Serialized) && attribute_type.subtype.nil? attribute name, ActiveRecord::Type::Serialized.new(ActiveRecord::Type::String.new, attribute_type.coder) end end @@ -369,23 +377,32 @@ # possibly keep track of decrypted attributes directly in the future # Hash serializer returns {} when nil, Array serializer returns [] when nil # check for this explicitly as a layer of safety if message.nil? || ((message == {} || message == []) && activerecord && @attributes[name.to_s].value_before_type_cast.nil?) ciphertext = send(encrypted_attribute) - message = self.class.send(decrypt_method_name, ciphertext, context: self) + # keep original message for empty hashes and arrays + unless ciphertext.nil? + message = self.class.send(decrypt_method_name, ciphertext, context: self) + end + if activerecord # set previous attribute so changes populate correctly # it's fine if this is set on future decryptions (as is the case when message is nil) # as only the first value is loaded into changes @attributes[name.to_s].instance_variable_set("@value_before_type_cast", message) # cache # decrypt method does type casting if respond_to?(:write_attribute_without_type_cast, true) write_attribute_without_type_cast(name.to_s, message) if !@attributes.frozen? - else + elsif respond_to?(:raw_write_attribute, true) raw_write_attribute(name, message) if !@attributes.frozen? + else + if !@attributes.frozen? + @attributes.write_cast_value(name.to_s, message) + clear_attribute_change(name) + end end else instance_variable_set("@#{name}", message) end end