Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Virtus::MultiparameterAttributes (extracted as gem: https://github.com/sj26/virtus-multiparams)
# Rails datetime_select and similar use multiparameter attributes which are
# these dawful things from the bowels of activerecord and actionpack. This
# module extends virtus models to coerce multiparameter attributes back together
# before assigning attributes.
#
# Here's the implementation for ActiveRecord:
#
# https://github.com/rails/rails/blob/11fd052aa815ae0255ea5b2463e88138fb3fec61/activerecord/lib/active_record/attribute_assignment.rb#L113-L218
#
# and DataMapper:
#
# https://github.com/datamapper/dm-rails/blob/5f3fb01a9d5f5adb17665a3bdabffd396d722e61/lib/dm-rails/multiparameter_attributes.rb
#
module Virtus::MultiparameterAttributes
def self.included(base)
base.attribute_set.singleton_class.send(:prepend, AttributeSetExtension)
end
module AttributeSetExtension
def coerce(attributes)
super(attributes).tap do |attributes|
multiparams = Hash.new { |hash, key| hash[key] = {} }
attributes.each do |(key, value)|
if /\A(?<name>.+)\((?<offset>[0-9]+)(?<cast>[if])?\)\Z/ =~ key
attributes.delete(key)
unless attributes.include? name
offset = offset.to_i
value = value.send("to_#{cast}") if cast
multiparams[name][offset] = value
end
end
end
multiparams.each do |name, values|
array = Array.new(values.keys.max)
values.each do |offset, value|
array[offset - 1] = value
end
# Virus::Attribute has a primitive type which might be Date, Time, DateTime, etc.
attribute = self[name]
attributes[name] = if attribute.primitive <= Date || attribute.primitive <= Time
# Basic convesion is enough, Virtus invokes `to_date[time]`
# Also, lololol timezones
Time.new(*array[0...6]) unless array[0...3].any?(&:blank?)
else
array
end
end
end
end
end
end
@aliang

This comment has been minimized.

Copy link
Owner Author

commented Mar 31, 2017

This is the same as the parent, except does not use ActiveSupport::Concern or alias_method_chain

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.