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