Skip to content

Instantly share code, notes, and snippets.

@stevehodges
Last active October 7, 2016 14:46
Show Gist options
  • Save stevehodges/dde0da195da29300e9a8bb3cfc337eb4 to your computer and use it in GitHub Desktop.
Save stevehodges/dde0da195da29300e9a8bb3cfc337eb4 to your computer and use it in GitHub Desktop.
attr_encrypted with Rails multiparameter attributes
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