This module contains the logic for handling the internal attributes hash, and how to get and set values.
Allows you to set all the attributes for a particular mass-assignment security role by passing in a hash of attributes with keys matching the attribute names (which again matches the column names) and the role name using the :as option. To bypass mass-assignment security you can use the :without_protection => true option.
@example Assign the attributes.
person.assign_attributes(:title => "Mr.")
@example Assign the attributes (with a role).
person.assign_attributes({ :title => "Mr." }, :as => :admin)
@param [ Hash ] attrs The new attributes to set. @param [ Hash ] options Supported options: :without_protection, :as
@since 2.2.1
# File lib/mongoid/attributes.rb, line 212 def assign_attributes(attrs = nil, options = {}) _assigning do process_attributes(attrs, options[:as] || :default, !options[:without_protection]) end end
Determine if an attribute is present.
@example Is the attribute present?
person.attribute_present?("title")
@param [ String, Symbol ] name The name of the attribute.
@return [ true, false ] True if present, false if not.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 26 def attribute_present?(name) attribute = read_attribute(name) !attribute.blank? || attribute == false end
Get the attributes that have not been cast.
@example Get the attributes before type cast.
document.attributes_before_type_cast
@return [ Hash ] The uncast attributes.
@since 3.1.0
# File lib/mongoid/attributes.rb, line 39 def attributes_before_type_cast @attributes_before_type_cast ||= {} end
Does the document have the provided attribute?
@example Does the document have the attribute?
model.has_attribute?(:name)
@param [ String, Symbol ] name The name of the attribute.
@return [ true, false ] If the key is present in the attributes.
@since 3.0.0
# File lib/mongoid/attributes.rb, line 53 def has_attribute?(name) attributes.has_key?(name.to_s) end
Does the document have the provided attribute before it was assigned and type cast?
@example Does the document have the attribute before it was assigned?
model.has_attribute_before_type_cast?(:name)
@param [ String, Symbol ] name The name of the attribute.
@return [ true, false ] If the key is present in the
attributes_before_type_cast.
@since 3.1.0
# File lib/mongoid/attributes.rb, line 69 def has_attribute_before_type_cast?(name) attributes_before_type_cast.has_key?(name.to_s) end
Read a value from the document attributes. If the value does not exist it will return nil.
@example Read an attribute.
person.read_attribute(:title)
@example Read an attribute (alternate syntax.)
person[:title]
@param [ String, Symbol ] name The name of the attribute to get.
@return [ Object ] The value of the attribute.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 87 def read_attribute(name) normalized = name.to_s if hash_dot_syntax?(normalized) attributes.__nested__(normalized) else attributes[normalized] end end
Read a value from the attributes before type cast. If the value has not yet been assigned then this will return the attribute's existing value using read_attribute.
@example Read an attribute before type cast.
person.read_attribute_before_type_cast(:price)
@param [ String, Symbol ] name The name of the attribute to get.
@return [ Object ] The value of the attribute before type cast, if
available. Otherwise, the value of the attribute.
@since 3.1.0
# File lib/mongoid/attributes.rb, line 110 def read_attribute_before_type_cast(name) attr = name.to_s if attributes_before_type_cast.has_key?(attr) attributes_before_type_cast[attr] else read_attribute(attr) end end
Remove a value from the Document
attributes. If the value does
not exist it will fail gracefully.
@example Remove the attribute.
person.remove_attribute(:title)
@param [ String, Symbol ] name The name of the attribute to remove.
@raise [ Errors::ReadonlyAttribute ] If the field cannot be removed due
to being flagged as reaodnly.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 131 def remove_attribute(name) access = name.to_s unless attribute_writable?(name) raise Errors::ReadonlyAttribute.new(name, :nil) end _assigning do attribute_will_change!(access) delayed_atomic_unsets[atomic_attribute_name(access)] = [] unless new_record? attributes.delete(access) end end
Override respond_to? so it responds properly for dynamic attributes.
@example Does this object respond to the method?
person.respond_to?(:title)
@param [ Array ] *args The name of the method.
@return [ true, false ] True if it does, false if not.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 153 def respond_to?(name, include_private = false) super || ( Mongoid.allow_dynamic_fields && attributes && attributes.has_key?(name.to_s.reader) && name.to_s.valid_method_name? ) end
Write a single attribute to the document attribute hash. This will also fire the before and after update callbacks, and perform any necessary typecasting.
@example Write the attribute.
person.write_attribute(:title, "Mr.")
@example Write the attribute (alternate syntax.)
person[:title] = "Mr."
@param [ String, Symbol ] name The name of the attribute to update. @param [ Object ] value The value to set for the attribute.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 176 def write_attribute(name, value) access = database_field_name(name.to_s) if attribute_writable?(access) _assigning do localized = fields[access].try(:localized?) attributes_before_type_cast[name.to_s] = value typed_value = typed_value_for(access, value) unless attributes[access] == typed_value || attribute_changed?(access) attribute_will_change!(access) end if localized (attributes[access] ||= {}).merge!(typed_value) else attributes[access] = typed_value end typed_value end end end
Writes the supplied attributes hash to the document. This will only
overwrite existing attributes if they are present in the new
Hash
, all others will be preserved.
@example Write the attributes.
person.write_attributes(:title => "Mr.")
@example Write the attributes (alternate syntax.)
person.attributes = { :title => "Mr." }
@param [ Hash ] attrs The new attributes to set. @param [ Boolean ] guard_protected_attributes False to skip mass assignment protection.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 232 def write_attributes(attrs = nil, guard_protected_attributes = true) assign_attributes(attrs, without_protection: !guard_protected_attributes) end
Define a reader method for a dynamic attribute before type cast.
@api private
@example Define a reader method for an attribute.
model.define_dynamic_before_type_cast_reader(:field)
@param [ String ] name The name of the field.
@since 3.1.0
# File lib/mongoid/attributes.rb, line 270 def define_dynamic_before_type_cast_reader(name) class_eval <<-READER def #{name}_before_type_cast attribute_will_change!(#{name.inspect}) read_attribute_before_type_cast(#{name.inspect}) end READER end
Define a reader method for a dynamic attribute.
@api private
@example Define a reader method.
model.define_dynamic_reader(:field)
@param [ String ] name The name of the field.
@since 3.0.0
# File lib/mongoid/attributes.rb, line 249 def define_dynamic_reader(name) return unless name.valid_method_name? class_eval <<-READER def #{name} attribute_will_change!(#{name.inspect}) read_attribute(#{name.inspect}) end READER end
Define a writer method for a dynamic attribute.
@api private
@example Define a writer method.
model.define_dynamic_writer(:field)
@param [ String ] name The name of the field.
@since 3.0.0
# File lib/mongoid/attributes.rb, line 289 def define_dynamic_writer(name) return unless name.valid_method_name? class_eval <<-WRITER def #{name}=(value) write_attribute(#{name.inspect}, value) end WRITER end
Does the string contain dot syntax for accessing hashes?
@api private
@example Is the string in dot syntax.
model.hash_dot_syntax?
@return [ true, false ] If the string contains a “.”
@since 3.0.15
# File lib/mongoid/attributes.rb, line 309 def hash_dot_syntax?(string) string =~ /\./ end
Used for allowing accessor methods for dynamic attributes.
@param [ String, Symbol ] name The name of the method. @param [ Array ] *args The arguments to the method.
# File lib/mongoid/attributes.rb, line 317 def method_missing(name, *args) attr = name.to_s return super unless attributes.has_key?(attr.reader) if attr.writer? getter = attr.reader define_dynamic_writer(getter) write_attribute(getter, args.first) elsif attr.before_type_cast? define_dynamic_before_type_cast_reader(attr.reader) attribute_will_change!(attr.reader) read_attribute_before_type_cast(attr.reader) else getter = attr.reader define_dynamic_reader(getter) attribute_will_change!(attr.reader) read_attribute(getter) end end
Return the typecasted value for a field.
@example Get the value typecasted.
person.typed_value_for(:title, :sir)
@param [ String, Symbol ] key The field name. @param [ Object ] value The uncast value.
@return [ Object ] The cast value.
@since 1.0.0
# File lib/mongoid/attributes.rb, line 347 def typed_value_for(key, value) fields.has_key?(key) ? fields[key].mongoize(value) : value.mongoize end