lib/lockbox/model.rb in lockbox-1.1.2 vs lib/lockbox/model.rb in lockbox-1.2.0
- old
+ new
@@ -17,14 +17,16 @@
# options[:type] = :string
# when Integer
# options[:type] = :integer
# when Float
# options[:type] = :float
+ # when BigDecimal
+ # options[:type] = :decimal
# end
custom_type = options[:type].respond_to?(:serialize) && options[:type].respond_to?(:deserialize)
- valid_types = [nil, :string, :boolean, :date, :datetime, :time, :integer, :float, :binary, :json, :hash, :array, :inet]
+ valid_types = [nil, :string, :boolean, :date, :datetime, :time, :integer, :float, :decimal, :binary, :json, :hash, :array, :inet]
raise ArgumentError, "Unknown type: #{options[:type]}" unless custom_type || valid_types.include?(options[:type])
activerecord = defined?(ActiveRecord::Base) && self < ActiveRecord::Base
raise ArgumentError, "Type not supported yet with Mongoid" if options[:type] && !activerecord
@@ -48,11 +50,11 @@
name = name.to_sym
options[:attribute] = name.to_s
options[:encrypted_attribute] = encrypted_attribute
- options[:encode] = true unless options.key?(:encode)
+ options[:encode] = Lockbox.encode_attributes unless options.key?(:encode)
encrypt_method_name = "generate_#{encrypted_attribute}"
decrypt_method_name = "decrypt_#{encrypted_attribute}"
class_eval do
@@ -319,13 +321,19 @@
options[:type]
end
attribute name, attribute_type
- serialize name, JSON if options[:type] == :json
- serialize name, Hash if options[:type] == :hash
- serialize name, Array if options[:type] == :array
+ if ActiveRecord::VERSION::STRING.to_f >= 7.1
+ serialize name, coder: JSON if options[:type] == :json
+ serialize name, type: Hash if options[:type] == :hash
+ serialize name, type: Array if options[:type] == :array
+ else
+ serialize name, JSON if options[:type] == :json
+ serialize name, Hash if options[:type] == :hash
+ serialize name, Array if options[:type] == :array
+ end
elsif !attributes_to_define_after_schema_loads.key?(name.to_s)
# when migrating it's best to specify the type directly
# however, we can try to use the original type if its already defined
if attributes_to_define_after_schema_loads.key?(original_name.to_s)
attribute name, attributes_to_define_after_schema_loads[original_name.to_s].first
@@ -529,10 +537,23 @@
message = [message].pack("q>")
when :float
message = ActiveRecord::Type::Float.new.serialize(message)
# double precision, big endian
message = [message].pack("G") unless message.nil?
+ when :decimal
+ message =
+ if ActiveRecord::VERSION::MAJOR >= 6
+ ActiveRecord::Type::Decimal.new.serialize(message)
+ else
+ # issue with serialize in Active Record < 6
+ # https://github.com/rails/rails/commit/a741208f80dd33420a56486bd9ed2b0b9862234a
+ ActiveRecord::Type::Decimal.new.cast(message)
+ end
+ # Postgres stores 4 decimal digits in 2 bytes
+ # plus 3 to 8 bytes of overhead
+ # but use string for simplicity
+ message = message.to_s("F") unless message.nil?
when :inet
unless message.nil?
ip = message.is_a?(IPAddr) ? message : (IPAddr.new(message) rescue nil)
# same format as Postgres, with ipv4 padded to 16 bytes
# family, netmask, ip
@@ -577,9 +598,11 @@
message = ActiveRecord::Type::Time.new.deserialize(message)
when :integer
message = ActiveRecord::Type::Integer.new(limit: 8).deserialize(message.unpack1("q>"))
when :float
message = ActiveRecord::Type::Float.new.deserialize(message.unpack1("G"))
+ when :decimal
+ message = ActiveRecord::Type::Decimal.new.deserialize(message)
when :string
message.force_encoding(Encoding::UTF_8)
when :binary
# do nothing
# decrypt returns binary string