require 'data_mapper/core' require 'data_mapper/validation' require 'data_mapper/validation/context' module DataMapper module Validation module ResourceExtensions # TODO: contemplate reworking dm-core to allow hooks to be fired even if # the hooked event does not transpire (eg., `before :save` when clean) # def self.included(model) # model.before :save, :validate_or_halt # end # Ensures the object is valid for the context provided, and otherwise # throws :halt and returns false. # # @param [Symbol] context # context for which to validate the Resource, defaulting to # #default_validation_context # # @return [Boolean] # whether the Resource was persisted successfully # # TODO: fix this to not change the method signature of #save # TODO: add support for skipping validations by passing nil # # @api public def save(context_name = default_validation_context) validation_rules.assert_valid_context(context_name) Context.in_context(context_name) { super() } end # @api private def save_self(*) return super unless dirty_self? || new? if Context.any? && !valid?(validation_rules.current_context) false else super end end # Ensures the object is valid for the context provided, and otherwise # throws :halt and returns false. # # @param [Hash] attributes # attribute names and values which will be set on this Resource # @param [Symbol] context # context for which to validate the Resource, defaulting to # #default_validation_context # # @return [Boolean] # whether the Resource attributes were set and persisted successfully # # TODO: fix this to not change the method signature of #update # # @api public def update(attributes = {}, context_name = default_validation_context) validation_rules.assert_valid_context(context_name) Context.in_context(context_name) { super(attributes) } end # @api public def validate(context_name = default_validation_context) super #validate_parents # if model.validation_rules.validate_parents? #validate_children # if model.validation_rules.validate_children? self end private # @api private def validate_parents parent_relationships.each do |relationship| next unless relationship.loaded?(self) validate_parent_relationship(relationship) end end # @api private def validate_children child_relationships.each do |relationship| next unless relationship.loaded?(self) validate_child_relationship(relationship) end end # @api private def validate_parent_relationship(relationship) relationship_name = relationship.name parent_model = relationship.target_model context_name = parent_model.validation_rules.current_context parent_resource = relationship.get(self) parent_violations = parent_resource.validation_violations(context_name) parent_violations.each { |v| errors[relationship_name] << v } end # @api private def validate_child_relationship(relationship) relationship_name = relationship.name child_model = relationship.target_model context_name = child_model.validation_rules.current_context child_collection = relationship.get_collection(self) child_collection.each do |child_resource| child_violations = child_resource.validation_violations(context_name) child_violations.each { |v| errors[relationship_name] << v } end end # @see note at self.included, above # # @api private # def validate_or_halt # throw :halt if Context.any? && !valid?(validation_rules.current_context) # end end # module Resource end # module Validation Model.append_inclusions Validation Model.append_inclusions Validation::ResourceExtensions end