Last active
October 7, 2016 14:46
-
-
Save stevehodges/dde0da195da29300e9a8bb3cfc337eb4 to your computer and use it in GitHub Desktop.
attr_encrypted with Rails multiparameter attributes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Widget < ActiveRecord::Base | |
## add data_class option when calling attr_encrypted | |
attr_encrypted :written_on, key: MY_SECURE_KEY, marshal: true, data_class: Date | |
end | |
## This monkeypatch of ActiveRecord ensures that Rails knows that `written_on` is a date when setting it via | |
## forms/assign_attributes. | |
## | |
## The problem: | |
## When submitted via form, the `written_on` attribute is submitted in parts, with these params: | |
## written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24" | |
## Since `written_on` is a virtual attribute, out of the box, Rails does not know how to set it as a Date. Thus, you'll | |
## hit MultiparameterAssignmentErrors when submitting your form and assigning attributes. | |
## See https://stackoverflow.com/questions/17482507/correct-way-to-handle-multiparameter-attributes-corresponding-to-virtual-attribu | |
## And this gist, which works for Rails < 4.2: https://gist.github.com/rcook/5992293 | |
## monkeypatch ActiveRecord (config/initializers) | |
class ActiveRecord::Base | |
def self.type_for_attribute(attr_name) | |
if encrypted_attributes[attr_name.to_sym] | |
encrypted_attribute_class_wrappers[attr_name.to_sym] || super(attr_name) | |
else | |
super(attr_name) | |
end | |
end | |
protected ################################################################### | |
class EncryptedAttributeClassWrapper | |
attr_reader :klass | |
def initialize(klass); @klass = klass; end | |
end | |
def self.encrypted_attribute_class_wrappers | |
@encrypted_attribute_class_wrappers ||= {} | |
end | |
singleton_class.send(:alias_method, :attr_encrypted_from_gem, :attr_encrypted) | |
def self.attr_encrypted(*args) | |
options = args.last.is_a?(Hash) ? args.pop : {} | |
encrypted_attribute_class_wrappers[args.first.to_sym] = EncryptedAttributeClassWrapper.new(options.delete(:data_class)) | |
new_args = args + [options] | |
attr_encrypted_from_gem *new_args | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment