2006-09-07 20:07:30 -04:00
|
|
|
module ActiveResource
|
|
|
|
class ResourceInvalid < ClientError
|
|
|
|
end
|
|
|
|
|
|
|
|
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) }
|
2006-09-20 05:34:29 -04:00
|
|
|
messages = Hash.from_xml(xml)['errors']['error'] rescue []
|
2006-09-07 20:07:30 -04:00
|
|
|
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 Validations
|
|
|
|
def self.included(base) # :nodoc:
|
|
|
|
base.class_eval do
|
|
|
|
alias_method_chain :save, :validation
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def save_with_validation
|
|
|
|
save_without_validation
|
2006-10-02 18:14:15 -04:00
|
|
|
rescue ResourceInvalid => error
|
|
|
|
errors.from_xml(error.response.body)
|
|
|
|
return false
|
2006-09-07 20:07:30 -04:00
|
|
|
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
|