mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
932e7b003c
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5962 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
161 lines
5.2 KiB
Ruby
161 lines
5.2 KiB
Ruby
module ActiveResource
|
|
class ResourceInvalid < ClientError #:nodoc:
|
|
end
|
|
|
|
# Active Resource validation is reported to and from this object, which is used by Base#save
|
|
# to determine whether the object in a valid state to be saved. See usage example in Validations.
|
|
class Errors
|
|
include Enumerable
|
|
attr_reader :errors
|
|
|
|
delegate :empty?, :to => :errors
|
|
|
|
def initialize(base) # :nodoc:
|
|
@base, @errors = base, {}
|
|
end
|
|
|
|
def add_to_base(msg)
|
|
add(:base, msg)
|
|
end
|
|
|
|
def add(attribute, msg)
|
|
@errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
|
|
@errors[attribute.to_s] << msg
|
|
end
|
|
|
|
# Returns true if the specified +attribute+ has errors associated with it.
|
|
def invalid?(attribute)
|
|
!@errors[attribute.to_s].nil?
|
|
end
|
|
|
|
# * Returns nil, if no errors are associated with the specified +attribute+.
|
|
# * Returns the error message, if one error is associated with the specified +attribute+.
|
|
# * Returns an array of error messages, if more than one error is associated with the specified +attribute+.
|
|
def on(attribute)
|
|
errors = @errors[attribute.to_s]
|
|
return nil if errors.nil?
|
|
errors.size == 1 ? errors.first : errors
|
|
end
|
|
|
|
alias :[] :on
|
|
|
|
# Returns errors assigned to base object through add_to_base according to the normal rules of on(attribute).
|
|
def on_base
|
|
on(:base)
|
|
end
|
|
|
|
# Yields each attribute and associated message per error added.
|
|
def each
|
|
@errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
|
|
end
|
|
|
|
# Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned
|
|
# through iteration as "First name can't be empty".
|
|
def each_full
|
|
full_messages.each { |msg| yield msg }
|
|
end
|
|
|
|
# Returns all the full error messages in an array.
|
|
def full_messages
|
|
full_messages = []
|
|
|
|
@errors.each_key do |attr|
|
|
@errors[attr].each do |msg|
|
|
next if msg.nil?
|
|
|
|
if attr == "base"
|
|
full_messages << msg
|
|
else
|
|
full_messages << [attr.humanize, msg].join(' ')
|
|
end
|
|
end
|
|
end
|
|
full_messages
|
|
end
|
|
|
|
def clear
|
|
@errors = {}
|
|
end
|
|
|
|
# Returns the total number of errors added. Two errors added to the same attribute will be counted as such
|
|
# with this as well.
|
|
def size
|
|
@errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
|
|
end
|
|
|
|
alias_method :count, :size
|
|
alias_method :length, :size
|
|
|
|
def from_xml(xml)
|
|
clear
|
|
humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
|
|
messages = Hash.from_xml(xml)['errors']['error'] rescue []
|
|
messages.each do |message|
|
|
attr_message = humanized_attributes.keys.detect do |attr_name|
|
|
if message[0, attr_name.size + 1] == "#{attr_name} "
|
|
add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
|
|
end
|
|
end
|
|
|
|
add_to_base message if attr_message.nil?
|
|
end
|
|
end
|
|
end
|
|
|
|
# Module to allow validation of ActiveResource objects, which are implemented by overriding +Base#validate+ or its variants.
|
|
# Each of these methods can inspect the state of the object, which usually means ensuring that a number of
|
|
# attributes have a certain value (such as not empty, within a given range, matching a certain regular expression). For example:
|
|
#
|
|
# class Person < ActiveResource::Base
|
|
# self.site = "http://www.localhost.com:3000/"
|
|
# protected
|
|
# def validate
|
|
# errors.add_on_empty %w( first_name last_name )
|
|
# errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
|
|
# end
|
|
#
|
|
# def validate_on_create # is only run the first time a new object is saved
|
|
# unless valid_member?(self)
|
|
# errors.add("membership_discount", "has expired")
|
|
# end
|
|
# end
|
|
#
|
|
# def validate_on_update
|
|
# errors.add_to_base("No changes have occurred") if unchanged_attributes?
|
|
# end
|
|
# end
|
|
#
|
|
# person = Person.new("first_name" => "Jim", "phone_number" => "I will not tell you.")
|
|
# person.save # => false (and doesn't do the save)
|
|
# person.errors.empty? # => false
|
|
# person.errors.count # => 2
|
|
# person.errors.on "last_name" # => "can't be empty"
|
|
# person.attributes = { "last_name" => "Halpert", "phone_number" => "555-5555" }
|
|
# person.save # => true (and person is now saved to the remote service)
|
|
#
|
|
# An Errors object is automatically created for every resource.
|
|
module Validations
|
|
def self.included(base) # :nodoc:
|
|
base.class_eval do
|
|
alias_method_chain :save, :validation
|
|
end
|
|
end
|
|
|
|
def save_with_validation
|
|
save_without_validation
|
|
true
|
|
rescue ResourceInvalid => error
|
|
errors.from_xml(error.response.body)
|
|
false
|
|
end
|
|
|
|
def valid?
|
|
errors.empty?
|
|
end
|
|
|
|
# Returns the Errors object that holds all information about attribute error messages.
|
|
def errors
|
|
@errors ||= Errors.new(self)
|
|
end
|
|
end
|
|
end
|