diff options
Diffstat (limited to 'activeresource/lib/active_resource')
-rw-r--r-- | activeresource/lib/active_resource/connection.rb | 4 | ||||
-rw-r--r-- | activeresource/lib/active_resource/validations.rb | 125 |
2 files changed, 128 insertions, 1 deletions
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb index 22689444b2..132e861292 100644 --- a/activeresource/lib/active_resource/connection.rb +++ b/activeresource/lib/active_resource/connection.rb @@ -71,7 +71,9 @@ module ActiveResource response when 404 raise(ResourceNotFound.new(response)) - when 400...500 + when 400 + raise(ResourceInvalid.new(response)) + when 401...500 raise(ClientError.new(response)) when 500...600 raise(ServerError.new(response)) diff --git a/activeresource/lib/active_resource/validations.rb b/activeresource/lib/active_resource/validations.rb new file mode 100644 index 0000000000..8414e93293 --- /dev/null +++ b/activeresource/lib/active_resource/validations.rb @@ -0,0 +1,125 @@ +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) } + messages = Hash.create_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 Validations + def self.included(base) # :nodoc: + base.class_eval do + alias_method_chain :save, :validation + end + end + + def save_with_validation + save_without_validation + rescue ResourceInvalid + errors.from_xml($!.response.body) + 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
\ No newline at end of file |