diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index d832027..7a292d3 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -161,34 +161,58 @@ module ActiveModel end end - # Adds an error message (+messsage+) to the +attribute+, which will be returned on a call to on(attribute) + class FullErrorMessage < String + attr_reader :message + def initialize(message) + super((@message = message).to_s) # in case of symbols... + end + + def full_message? + true + end + end + + # Adds an error message (+message+) to the +attribute+, which will be returned on a call to on(attribute) # for the same attribute and ensure that this error object returns false when asked if empty?. More than one # error can be added to the same +attribute+ in which case an array will be returned on a call to on(attribute). - # If no +messsage+ is supplied, :invalid is assumed. - # + # If no +message+ is supplied, :invalid is assumed. Pass +:full_message => true+ in the options for specifying + # it is the full message, so that the attribute is not prepended in full_messages. + # # If +message+ is a Symbol, it will be translated, using the appropriate scope (see translate_error). # If +message+ is a Proc, it will be called, allowing for things like Time.now to be used within an error def add(attribute, message = nil, options = {}) message ||= :invalid message = generate_message(attribute, message, options) if message.is_a?(Symbol) message = message.call if message.is_a?(Proc) + message = FullErrorMessage.new message if options[:full_message] self[attribute] << message end + def generate_full_message(attribute, message) + message = message.message if message.respond_to? :message + return (message.is_a?(Symbol) ? I18n.t(message) : message) if attribute == :base or (predicate.full_message? rescue false) + + attr_name = attribute.to_s.gsub('.', '_').humanize + attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) + options = { :default => "{{attribute}} {{message}}", :attribute => attr_name } + + I18n.t(:"errors.format", options.merge(:message => message)) + end + # Will add an error message to each of the attributes in +attributes+ that is empty. - def add_on_empty(attributes, custom_message = nil) + def add_on_empty(attributes, custom_message = nil, options = {}) [attributes].flatten.each do |attribute| value = @base.send(:read_attribute_for_validation, attribute) is_empty = value.respond_to?(:empty?) ? value.empty? : false - add(attribute, :empty, :default => custom_message) unless !value.nil? && !is_empty + add(attribute, :empty, options.merge(:default => custom_message)) unless !value.nil? && !is_empty end end # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?). - def add_on_blank(attributes, custom_message = nil) + def add_on_blank(attributes, custom_message = nil, options = {}) [attributes].flatten.each do |attribute| value = @base.send(:read_attribute_for_validation, attribute) - add(attribute, :blank, :default => custom_message) if value.blank? + add(attribute, :blank, options.merge(:default => custom_message)) if value.blank? end end @@ -206,20 +230,8 @@ module ActiveModel full_messages = [] each do |attribute, messages| - messages = Array(messages) - next if messages.empty? - - if attribute == :base - messages.each {|m| full_messages << m } - else - attr_name = attribute.to_s.gsub('.', '_').humanize - attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) - options = { :default => "{{attribute}} {{message}}", :attribute => attr_name } - - messages.each do |m| - full_messages << I18n.t(:"errors.format", options.merge(:message => m)) - end - end + messages = Array.wrap(messages) + messages.each {|m| full_messages << generate_full_message(attribute, m)} end full_messages diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index 0423fcd..dcb8ef5 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -7,7 +7,7 @@ module ActiveModel def validate_each(record, attribute, value) unless value == options[:accept] - record.errors.add(attribute, :accepted, :default => options[:message]) + add_error(record, attribute, :accepted) end end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 8041d4b..aa170f3 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -4,7 +4,7 @@ module ActiveModel def validate_each(record, attribute, value) confirmed = record.send(:"#{attribute}_confirmation") return if confirmed.nil? || value == confirmed - record.errors.add(attribute, :confirmation, :default => options[:message]) + add_error(record, attribute, :confirmation) end def setup(klass) diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 7ee718c..ebb67d8 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) return unless options[:in].include?(value) - record.errors.add(attribute, :exclusion, :default => options[:message], :value => value) + add_error(record, attribute, :exclusion, :value => value) end end diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 9a9e7ec..b8dc3ff 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -2,11 +2,8 @@ module ActiveModel module Validations class FormatValidator < EachValidator def validate_each(record, attribute, value) - if options[:with] && value.to_s !~ options[:with] - record.errors.add(attribute, :invalid, :default => options[:message], :value => value) - elsif options[:without] && value.to_s =~ options[:without] - record.errors.add(attribute, :invalid, :default => options[:message], :value => value) - end + add_error(record, attribute, :invalid, :value => value) if + (options[:with] && value.to_s !~ options[:with]) or (options[:without] && value.to_s =~ options[:without]) end def check_validity! diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 0c1334f..9f19d36 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -8,7 +8,7 @@ module ActiveModel def validate_each(record, attribute, value) return if options[:in].include?(value) - record.errors.add(attribute, :inclusion, :default => options[:message], :value => value) + add_error(record, attribute, :inclusion, :value => value) end end diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 9ceb754..cdbae7f 100644 --- a/activemodel/lib/active_model/validations/length.rb +++ b/activemodel/lib/active_model/validations/length.rb @@ -37,7 +37,7 @@ module ActiveModel CHECKS.each do |key, validity_check| next unless check_value = options[key] - custom_message = options[:message] || options[MESSAGES[key]] + custom_message = message || options[MESSAGES[key]] valid_value = if key == :maximum value.nil? || value.size.send(validity_check, check_value) @@ -46,7 +46,7 @@ module ActiveModel end next if valid_value - record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value) + add_error(record, attribute, MESSAGES[key], :default => custom_message, :count => check_value) end end end diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index c6d84c5..99448b3 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -26,7 +26,7 @@ module ActiveModel return if options[:allow_nil] && raw_value.nil? unless value = parse_raw_value(raw_value, options) - record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message]) + add_error(record, attr_name, :not_a_number, :value => raw_value) return end @@ -34,14 +34,14 @@ module ActiveModel case option when :odd, :even unless value.to_i.send(CHECKS[option]) - record.errors.add(attr_name, option, :value => value, :default => options[:message]) + add_error(record, attr_name, option, :value => value) end else option_value = option_value.call(record) if option_value.is_a?(Proc) option_value = record.send(option_value) if option_value.is_a?(Symbol) unless value.send(CHECKS[option], option_value) - record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value) + add_error(record, attr_name, option, :value => value, :count => option_value) end end end diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index 4a71cf7..624c88e 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -4,7 +4,7 @@ module ActiveModel module Validations class PresenceValidator < EachValidator def validate(record) - record.errors.add_on_blank(attributes, options[:message]) + add_on_blank_error record end end diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index b61f0cb..57452de 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -158,6 +158,21 @@ module ActiveModel #:nodoc: # ArgumentError when invalid options are supplied. def check_validity! end + + def message + options[:full_message] || options[:message] + end + + def add_error(record, attribute, error_message, error_options={}) + opts = {:default => message} + opts.merge! :full_message => !!options[:full_message] if options[:full_message] + record.errors.add(attribute, error_message, opts.merge(error_options)) + end + + def add_on_blank_error(record) + opts = options[:full_message] ? {:full_message => true} : {} + record.errors.add_on_blank attributes, message, opts + end end # BlockValidator is a special EachValidator which receives a block on initialization