symmetric-encryption
symmetric-encryption copied to clipboard
Accepting Multi-Parameter time values for an encrypted field cast to :date (Rails)
Hi there, with a regular (non-encrypted) date based field, when I use form helpers, I end up with 3 select boxes that are named something like this:
field(1i) #year
field(2i) #month
field(3i) #day
In Active Record, Rails looks at the db column ,and figure out that field can accept a hash and parse that into a date. Check out here and here.
Essentially it passes in to the attribute setter a hash of values:
{1=>1975, 2=> 11, 3=>9} # this would imply a date 9/11/75
It would be great if when I set a field type
attr_encrypted :date_of_birth, type: :date
Then I could hope to see that sort of behavior. I'm not sure if you guys consider this too framework specific, but if you think it's a worthwhile feature, would be glad to figure out a PR for it
I tried this out for regular Active Record models and they do not convert the hash above into a date in the model. In fact after saving the model the Hash date is just lost and returns from the database as nil.
2.3.1 :026 > i = X.new(expire_alert: {1=>1975, 2=> 11, 3=>9})
#<X:0x007fa0aebe2b60> {
:expire_alert => {
1 => 1975,
2 => 11,
3 => 9
},
}
2.3.1 :027 > i.save
true
2.3.1 :028 > i.reload
#<X:0x007fa0aebe2b60> {
:expire_alert => nil,
}
I'll take a look into this when I get a moment - just to make sure we are on the same page, in your sample above, X is an ActiveRecord class with an expire_alert field mapping to column type :date right?
Yes, I replaced the model name in the output with X since it is an actual model in our application that has a date column. We are running Rails 4.2. Also removed all other columns from the output.
This should work it around:
def expiry_date=(date)
if date.is_a? Hash
super Date.new(*date.values)
else
super
end
end
Sorry - haven't had a chance to do you a minimal example to reproduce yet @reidmorrison, but yes @PascalSenn for working around it I just do:
def some_encrypted_date_field=(value)
super(hash_to_date(value))
end
edit: We implemented hash_to_date, method shown 2 comments down
hash_to_date is the internal function ActiveRecord uses to parse input
@eyefodder This seems not to work for me.
NameError Exception: undefined local variable or method `hash_to_date' for ...
Couldn't find this method in the codebase neither.
Rails, 4.2.4 which version are you using?
ugh - sorry - my bad... So looked a little deeper into how we had implemented. The class ActiveModel::Type::Helpers::AcceptsMultiparameterTime is where they implement the hash to date parsing using a method value_from_multiparameter_assignment
We pretty much lifted that code to implement in a field that is encypted with this method:
#@see ActiveModel::Type::Helpers::AcceptsMultiparameterTime
def hash_to_date(value)
return value unless value.is_a?(Hash)
return value unless value[1] && value[2] && value[3]
values = value.sort.map(&:last)
::Time.send(default_timezone, *values)
end