class Mongoid::Validatable::AssociatedValidator
Validates whether or not an association is valid or not. Will correctly handle has one and has many associations.
@example Set up the association validations.
class Person include Mongoid::Document embeds_one :name embeds_many :addresses validates_associated :name, :addresses end
Public Instance Methods
Required by ‘validates_with` so that the validator gets added to the correct attributes.
# File lib/mongoid/validatable/associated.rb, line 22 def attributes options[:attributes] end
Checks that the named associations of the given record (‘attributes`) are valid. This does NOT load the associations from the database, and will only validate records that are dirty or unpersisted.
If anything is not valid, appropriate errors will be added to the ‘document` parameter.
@param [ Mongoid::Document
] document the document with the
associations to validate.
# File lib/mongoid/validatable/associated.rb, line 36 def validate(document) options[:attributes].each do |attr_name| validate_association(document, attr_name) end end
Private Instance Methods
Examine the given target object and return an array of documents (possibly empty) that the target represents.
@param [ Array | Mongoid::Document
| Mongoid::Association::Proxy
| HasMany::Enumerable ] target
the target object to examine.
@return [ Array<Mongoid::Document> ] the list of documents
# File lib/mongoid/validatable/associated.rb, line 97 def get_target_documents(target) if target.respond_to?(:_loaded?) get_target_documents_for_has_many(target) else get_target_documents_for_other(target) end end
Returns the list of all currently in-memory values held by the target. The target will not be loaded.
@param [ HasMany::Enumerable ] target the target that will
be examined for in-memory documents.
@return [ Array<Mongoid::Document> ] the in-memory documents
held by the target.
# File lib/mongoid/validatable/associated.rb, line 113 def get_target_documents_for_has_many(target) [ *target._loaded.values, *target._added.values ] end
Returns the target as an array. If the target represents a single value, it is wrapped in an array.
@param [ Array | Mongoid::Document
| Mongoid::Association::Proxy
] target
the target to return.
@return [ Array<Mongoid::Document> ] the target, as an array.
# File lib/mongoid/validatable/associated.rb, line 124 def get_target_documents_for_other(target) Array.wrap(target) end
Validates that the given association provided is either nil, persisted and unchanged, or invalid. Otherwise, the appropriate errors will be added to the parent document.
@param [ Document
] document The document to validate. @param [ Symbol ] attribute The association to validate.
# File lib/mongoid/validatable/associated.rb, line 50 def validate_association(document, attribute) # grab the proxy from the instance variable directly; we don't want # any loading logic to run; we just want to see if it's already # been loaded. proxy = document.ivar(attribute) return unless proxy # if the variable exists, now we see if it is a proxy, or an actual # document. It might be a literal document instead of a proxy if this # document was created with a Document instance as a provided attribute, # e.g. "Post.new(message: Message.new)". target = proxy.respond_to?(:_target) ? proxy._target : proxy # Now, fetch the list of documents from the target. Target may be a # single value, or a list of values, and in the case of HasMany, # might be a rather complex collection. We need to do this without # triggering a load, so it's a bit of a delicate dance. list = get_target_documents(target) valid = document.validating do # Now, treating the target as an array, look at each element # and see if it is valid, but only if it has already been # persisted, or changed, and hasn't been flagged for destroy. # # use map.all? instead of just all?, because all? will do short-circuit # evaluation and terminate on the first failed validation. list.map do |value| if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?) value.validated? ? true : value.valid? else true end end.all? end document.errors.add(attribute, :invalid) unless valid end