From eeac5d61532d3d69713b96472ea8445e06fd6a5d Mon Sep 17 00:00:00 2001 From: Rodrigo Rosenfeld Rosas Date: Thu, 21 Jan 2010 17:06:02 -0200 Subject: [PATCH] Include support for :full_message option to validations. --- activemodel/lib/active_model/errors.rb | 53 ++++++++++++++------ .../lib/active_model/validations/acceptance.rb | 2 +- .../lib/active_model/validations/confirmation.rb | 2 +- .../lib/active_model/validations/exclusion.rb | 2 +- activemodel/lib/active_model/validations/format.rb | 4 +- .../lib/active_model/validations/inclusion.rb | 2 +- activemodel/lib/active_model/validations/length.rb | 2 +- .../lib/active_model/validations/numericality.rb | 6 +- .../lib/active_model/validations/presence.rb | 2 +- activemodel/lib/active_model/validator.rb | 5 ++ 10 files changed, 53 insertions(+), 27 deletions(-) diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 2e5bcab..8eebe5c 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -55,19 +55,52 @@ module ActiveModel end end - # Adds an error message (+messsage+) to the +attribute+, which will be returned on a call to on(attribute) + class ErrorMessage + attr_reader :options, :message + def initialize(options) + @options = options.is_a?(Hash) ? options : {:message => options} + @message = options[:full_message] || options[:message] + end + + def full_message? + !!options[:full_message] + end + end + + module FullErrorMessage + 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. # 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 + full_message = false + if (default=options[:default]).is_a? ErrorMessage + full_message = default.full_message? + options[:default] = default.message + end message = generate_message(attribute, message, options) if message.is_a?(Symbol) message = message.call if message.is_a?(Proc) + message.extend(FullErrorMessage) if full_message self[attribute] << message end + def generate_full_message(attribute, predicate) + return predicate.to_s 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 => predicate)) + end + # Will add an error message to each of the attributes in +attributes+ that is empty. def add_on_empty(attributes, custom_message = nil) [attributes].flatten.each do |attribute| @@ -99,20 +132,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..d02a9e3 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]) + record.errors.add(attribute, :accepted, :default => message) end end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 8041d4b..37649ee 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]) + record.errors.add(attribute, :confirmation, :default => message) end def setup(klass) diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 7ee718c..8bc2cf9 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) + record.errors.add(attribute, :exclusion, :default => message, :value => value) end end diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index 9a9e7ec..f92d51b 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -3,9 +3,9 @@ module ActiveModel 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) + record.errors.add(attribute, :invalid, :default => message, :value => value) elsif options[:without] && value.to_s =~ options[:without] - record.errors.add(attribute, :invalid, :default => options[:message], :value => value) + record.errors.add(attribute, :invalid, :default => message, :value => value) end end diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 0c1334f..f8bcf73 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) + record.errors.add(attribute, :inclusion, :default => message, :value => value) end end diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb index 9ceb754..c7ea251 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) diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index c6d84c5..95e71b8 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]) + record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => message) 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]) + record.errors.add(attr_name, option, :value => value, :default => message) 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) + record.errors.add(attr_name, option, :default => message, :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..3f4a846 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]) + record.errors.add_on_blank(attributes, message) end end diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index 382a4cc..6df1845 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -139,6 +139,11 @@ module ActiveModel #:nodoc: # ArgumentError when invalid options are supplied. def check_validity! end + + def message + return nil unless options[:full_message] || options[:message] + @message ||= Errors::ErrorMessage.new(options) + end end # BlockValidator is a special EachValidator which receives a block on initialization -- 1.6.6