Skip to content

Commit

Permalink
Make ActiveModel::Errors#add_on_blank and #add_on_empty accept an opt…
Browse files Browse the repository at this point in the history
…ions hash and make various Validators pass their (filtered) options.

This makes it possible to pass additional options through Validators to message
generation. E.g. plugin authors want to add validates_presence_of :foo, :format
=> "some format".

Also, cleanup the :default vs :message options confusion in ActiveModel
validation message generation.

Also, deprecate ActiveModel::Errors#add_on_blank(attributes, custom_message) in
favor of ActiveModel::Errors#add_on_blank(attributes, options).

Original patch by Sven Fuchs, some minor changes and has been changed to be applicable to master again

[#4057 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information
jeroenvandijk authored and jeremy committed May 15, 2010
1 parent 47c9a35 commit bc1c8d5
Show file tree
Hide file tree
Showing 15 changed files with 139 additions and 111 deletions.
54 changes: 41 additions & 13 deletions activemodel/lib/active_model/errors.rb
Expand Up @@ -179,25 +179,45 @@ def to_xml(options={})
# 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)

reserved = [:minimum, :maximum, :is, :within , :in, :allow_nil, :allow_blank, :case_sensitive,
:too_long, :too_short, :wrong_length, :on, :if, :unless , :tokenizer, :invalid,
:only_integer, :odd, :even, :less_than, :with, :accept]

message = generate_message(attribute, message, options.except(*reserved)) if message.is_a?(Symbol)

message = message.call if message.is_a?(Proc)
self[attribute] << 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, options = {})
if options && !options.is_a?(Hash)
options = { :message => options }
ActiveSupport::Deprecation.warn \
"ActiveModel::Errors#add_on_empty(attributes, custom_message) has been deprecated.\n" +
"Instead of passing a custom_message pass an options Hash { :message => custom_message }."
end

[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) if 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, options = {})
if options && !options.is_a?(Hash)
options = { :message => options }
ActiveSupport::Deprecation.warn \
"ActiveModel::Errors#add_on_blank(attributes, custom_message) has been deprecated.\n" +
"Instead of passing a custom_message pass an options Hash { :message => custom_message }."
end

[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) if value.blank?
end
end

Expand Down Expand Up @@ -254,18 +274,26 @@ def full_messages
# <li><tt>errors.attributes.title.blank</tt></li>
# <li><tt>errors.messages.blank</tt></li>
# </ol>
def generate_message(attribute, message = :invalid, options = {})
message, options[:default] = options[:default], message if options[:default].is_a?(Symbol)

def generate_message(attribute, type = :invalid, options = {})
type = options.delete(:message) if options[:message].is_a?(Symbol)

if options[:default]
ActiveSupport::Deprecation.warn \
"ActiveModel::Errors#generate_message(attributes, custom_message) has been deprecated.\n" +
"Use ActiveModel::Errors#generate_message(attributes, :message => 'your message') instead."
options[:message] = options.delete(:default)
end

defaults = @base.class.lookup_ancestors.map do |klass|
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{message}",
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{message}" ]
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.attributes.#{attribute}.#{type}",
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.underscore}.#{type}" ]
end

defaults << options.delete(:default)
defaults << :"#{@base.class.i18n_scope}.errors.messages.#{message}"
defaults << :"errors.attributes.#{attribute}.#{message}"
defaults << :"errors.messages.#{message}"
defaults << options.delete(:message)
defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}"
defaults << :"errors.attributes.#{attribute}.#{type}"
defaults << :"errors.messages.#{type}"

defaults.compact!
defaults.flatten!
Expand Down
2 changes: 1 addition & 1 deletion activemodel/lib/active_model/validations/acceptance.rb
Expand Up @@ -7,7 +7,7 @@ def initialize(options)

def validate_each(record, attribute, value)
unless value == options[:accept]
record.errors.add(attribute, :accepted, :default => options[:message])
record.errors.add(attribute, :accepted, options)
end
end

Expand Down
2 changes: 1 addition & 1 deletion activemodel/lib/active_model/validations/confirmation.rb
Expand Up @@ -4,7 +4,7 @@ class ConfirmationValidator < EachValidator
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, options)
end

def setup(klass)
Expand Down
2 changes: 1 addition & 1 deletion activemodel/lib/active_model/validations/exclusion.rb
Expand Up @@ -8,7 +8,7 @@ def check_validity!

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, options.merge(:value => value))
end
end

Expand Down
4 changes: 2 additions & 2 deletions activemodel/lib/active_model/validations/format.rb
Expand Up @@ -3,9 +3,9 @@ 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)
record.errors.add(attribute, :invalid, options.merge(: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, options.merge(:value => value))
end
end

Expand Down
2 changes: 1 addition & 1 deletion activemodel/lib/active_model/validations/inclusion.rb
Expand Up @@ -8,7 +8,7 @@ def check_validity!

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, options.merge(:value => value))
end
end

Expand Down
4 changes: 2 additions & 2 deletions activemodel/lib/active_model/validations/length.rb
Expand Up @@ -37,7 +37,7 @@ def validate_each(record, attribute, value)

CHECKS.each do |key, validity_check|
next unless check_value = options[key]
custom_message = options[:message] || options[MESSAGES[key]]
options[:message] ||= options[MESSAGES[key]] if options[MESSAGES[key]]

valid_value = if key == :maximum
value.nil? || value.size.send(validity_check, check_value)
Expand All @@ -46,7 +46,7 @@ def validate_each(record, attribute, value)
end

next if valid_value
record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value)
record.errors.add(attribute, MESSAGES[key], options.merge(:count => check_value))
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions activemodel/lib/active_model/validations/numericality.rb
Expand Up @@ -26,13 +26,13 @@ def validate_each(record, attr_name, value)
return if options[:allow_nil] && raw_value.nil?

unless value = parse_raw_value_as_a_number(raw_value)
record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
record.errors.add(attr_name, :not_a_number, options.merge(:value => raw_value))
return
end

if options[:only_integer]
unless value = parse_raw_value_as_an_integer(raw_value)
record.errors.add(attr_name, :not_an_integer, :value => raw_value, :default => options[:message])
record.errors.add(attr_name, :not_an_integer, options.merge(:value => raw_value))
return
end
end
Expand All @@ -41,14 +41,14 @@ def validate_each(record, attr_name, value)
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, options.merge(: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)
record.errors.add(attr_name, option, options.merge(:value => value, :count => option_value))
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion activemodel/lib/active_model/validations/presence.rb
Expand Up @@ -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, options)
end
end

Expand Down

0 comments on commit bc1c8d5

Please sign in to comment.