Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accepting Multi-Parameter time values for an encrypted field cast to :date (Rails) #62

Open
eyefodder opened this issue Aug 31, 2016 · 7 comments

Comments

@eyefodder
Copy link

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

@reidmorrison
Copy link
Owner

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,
}

@eyefodder
Copy link
Author

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?

@reidmorrison
Copy link
Owner

reidmorrison commented Oct 13, 2016

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.

@PascalSenn
Copy link

PascalSenn commented Nov 21, 2016

This should work it around:

  def expiry_date=(date)
    if date.is_a? Hash
      super Date.new(*date.values)
    else
      super
    end
  end

@eyefodder
Copy link
Author

eyefodder commented Nov 21, 2016

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

@PascalSenn
Copy link

PascalSenn commented Nov 22, 2016

@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?

@eyefodder
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants