parsley/app/models/concerns/default_values.rb
Dan Elbert 18603dc783
Some checks failed
parsley/pipeline/head There was a failure building this commit
tasks
2018-09-06 18:16:13 -05:00

95 lines
2.8 KiB
Ruby

# == Default Values
#
# Allows default attributes values to be declared. The callback used to set the values can be controlled via options.
#
# The following option keys are allowed:
# `:on`. If omitted, it defaults to :initialize.
# :on may be one of the following: :initialize, :create, :update, :save
#
# `:empty`. If omitted, it defaults to only updating `nil` values
# :empty should be a lambda (or proc) that accepts the current value of the attribute and returns true if the value
# should be replaced by the default
#
# Examples:
# Sets `attr` to 'default' and `attr2` to 'default' any time the class is instantiated
# default_values {
# attr: 'default',
# attr2: 'default'
# }
#
# Sets `roles` to [:super_admin] only when saving a new object and only if roles is an empty array (it will not update a nil value)
# default_values({roles: [:super_admin]}, {on: :create, empty: ->(v) { v == [] }})
#
module DefaultValues
extend ActiveSupport::Concern
DEFAULT_OPTIONS = { on: :initialize }
DefaultValue = Struct.new(:value, :options)
included do
class_attribute :_default_values
self._default_values = {}
after_initialize :set_default_values_initialize
before_create :set_default_values_create
before_update :set_default_values_update
before_save :set_default_values_save
end
def set_default_values_initialize
set_default_values(:initialize)
end
def set_default_values_create
set_default_values(:create)
end
def set_default_values_update
set_default_values(:update)
end
def set_default_values_save
set_default_values(:save)
end
def set_default_values(on)
_default_values.each do |k, dv|
if dv.options[:on].to_sym == on
v = dv.value
v_lambda = Proc === v ? v : -> { v }
tester = dv.options[:empty] || ->(x) { x.nil? }
self.send("#{k}=", self.instance_exec(&v_lambda)) if self.respond_to?(k) && tester.call(self.send(k))
end
end
end
module ClassMethods
# Copy defaults on inheritance.
def inherited(base)
base._default_values = _default_values.dup
super
end
def default_values(defaults_hash, options = {})
options = DEFAULT_OPTIONS.merge(options.symbolize_keys)
valid_ons = [:initialize, :create, :update, :save]
unless valid_ons.include? options[:on]
raise "Invalid options[:on] value: [#{options[:on]}]. Must be one of these symbols: #{valid_ons.join(', ')}"
end
if options[:empty].present?
proc = options[:empty]
raise "Invalid options[:empty]. Must be a Proc or Lambda with an arity of 1" unless (proc.is_a?(Proc) && proc.arity == 1)
end
defaults_hash.each do |k, v|
_default_values[k] = DefaultValue.new(v, options)
end
end
end
end