lib/mongoid/attributes/processing.rb
# encoding: utf-8
module Mongoid
module Attributes
# This module contains the behavior for processing attributes.
module Processing
# Process the provided attributes casting them to their proper values if a
# field exists for them on the document. This will be limited to only the
# attributes provided in the suppied +Hash+ so that no extra nil values get
# put into the document's attributes.
#
# @example Process the attributes.
# person.process_attributes(:title => "sir", :age => 40)
#
# @param [ Hash ] attrs The attributes to set.
#
# @since 2.0.0.rc.7
def process_attributes(attrs = nil)
attrs ||= {}
if !attrs.empty?
attrs = sanitize_for_mass_assignment(attrs)
attrs.each_pair do |key, value|
next if pending_attribute?(key, value)
process_attribute(key, value)
end
end
yield self if block_given?
process_pending
end
private
# If the key provided is the name of a relation or a nested attribute, we
# need to wait until all other attributes are set before processing
# these.
#
# @example Is the attribute pending?
# document.pending_attribute?(:name, "Durran")
#
# @param [ Symbol ] key The name of the attribute.
# @param [ Object ] value The value of the attribute.
#
# @return [ true, false ] True if pending, false if not.
#
# @since 2.0.0.rc.7
def pending_attribute?(key, value)
name = key.to_s
if relations.has_key?(name)
pending_relations[name] = value
return true
end
if nested_attributes.has_key?(name)
pending_nested[name] = value
return true
end
return false
end
# Get all the pending relations that need to be set.
#
# @example Get the pending relations.
# document.pending_relations
#
# @return [ Hash ] The pending relations in key/value pairs.
#
# @since 2.0.0.rc.7
def pending_relations
@pending_relations ||= {}
end
# Get all the pending nested attributes that need to be set.
#
# @example Get the pending nested attributes.
# document.pending_nested
#
# @return [ Hash ] The pending nested attributes in key/value pairs.
#
# @since 2.0.0.rc.7
def pending_nested
@pending_nested ||= {}
end
# If the attribute is dynamic, add a field for it with a type of object
# and then either way set the value.
#
# @example Process the attribute.
# document.process_attribute(name, value)
#
# @param [ Symbol ] name The name of the field.
# @param [ Object ] value The value of the field.
#
# @since 2.0.0.rc.7
def process_attribute(name, value)
if !respond_to?("#{name}=", true) && store_as = aliased_fields.invert[name.to_s]
name = store_as
end
responds = respond_to?("#{name}=", true)
raise Errors::UnknownAttribute.new(self.class, name) unless responds
send("#{name}=", value)
end
# Process all the pending nested attributes that needed to wait until
# ids were set to fire off.
#
# @example Process the nested attributes.
# document.process_nested
#
# @since 2.0.0.rc.7
def process_nested
pending_nested.each_pair do |name, value|
send("#{name}=", value)
end
end
# Process all the pending items, then clear them out.
#
# @example Process the pending items.
# document.process_pending
#
# @param [ Hash ] options The mass assignment options.
#
# @since 2.0.0.rc.7
def process_pending
process_nested and process_relations
pending_nested.clear and pending_relations.clear
end
# Process all the pending relations that needed to wait until ids were set
# to fire off.
#
# @example Process the relations.
# document.process_relations
#
# @param [ Hash ] options The mass assignment options.
#
# @since 2.0.0.rc.7
def process_relations
pending_relations.each_pair do |name, value|
metadata = relations[name]
if value.is_a?(Hash)
metadata.nested_builder(value, {}).build(self)
else
send("#{name}=", value)
end
end
end
end
end
end