Ticket #8139: active_record_identified_validations.6545.diff
| File active_record_identified_validations.6545.diff, 14.1 kB (added by divoxx, 2 years ago) |
|---|
-
activerecord/lib/active_record/validations.rb
old new 19 19 class Errors 20 20 include Enumerable 21 21 22 class ErrorMessage 23 def self.extract_message(error_base, message, *args) 24 message = error_base.class.default_error_messages[message] if message.is_a?(Symbol) 25 args.empty? ? message : message % args 26 end 27 28 attr_reader :message 29 alias_method :to_s, :message 30 31 def initialize(error_base, message, *args) 32 @msg_id = message 33 @message = self.class.extract_message(error_base, message, *args) 34 end 35 36 def message_id 37 @msg_id 38 end 39 40 def ==(other) 41 case other 42 when ErrorMessage 43 self.message_id == other.message_id 44 when Symbol 45 self.message_id == other 46 else 47 self.message == other.to_s 48 end 49 end 50 51 end 52 22 53 def initialize(base) # :nodoc: 23 54 @base, @errors = base, {} 24 55 end … … 50 81 add(:base, msg) 51 82 end 52 83 53 # Adds an error message (+msg+) to the +attribute+, which will be returned on a call to <tt>on(attribute)</tt>84 # Adds an error message identifier (+msg_id+) to the +attribute+, which will be returned on a call to <tt>on(attribute)</tt> 54 85 # for the same attribute and ensure that this error object returns false when asked if <tt>empty?</tt>. More than one 55 86 # error can be added to the same +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>. 56 # If no +msg + is supplied, "invalid"is assumed.57 def add(attribute, msg = @@default_error_messages[:invalid])87 # If no +msg_id+ is supplied, :invalid is assumed. 88 def add(attribute, msg_id = :invalid, *args) 58 89 @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil? 59 @errors[attribute.to_s] << msg90 @errors[attribute.to_s] << ErrorMessage.new(self, msg_id, *args) 60 91 end 61 92 62 93 # Will add an error message to each of the attributes in +attributes+ that is empty. 63 def add_on_empty(attributes, msg = @@default_error_messages[:empty])94 def add_on_empty(attributes, msg_id = :empty) 64 95 for attr in [attributes].flatten 65 96 value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] 66 is_empty = value.respond_to?( "empty?") ? value.empty? : false67 add(attr, msg ) unless !value.nil? && !is_empty97 is_empty = value.respond_to?(:empty?) ? value.empty? : false 98 add(attr, msg_id) unless !value.nil? && !is_empty 68 99 end 69 100 end 70 101 71 102 # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?). 72 def add_on_blank(attributes, msg = @@default_error_messages[:blank])103 def add_on_blank(attributes, msg_id = :blank) 73 104 for attr in [attributes].flatten 74 105 value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] 75 add(attr, msg ) if value.blank?106 add(attr, msg_id) if value.blank? 76 107 end 77 108 end 78 109 79 110 # Will add an error message to each of the attributes in +attributes+ that has a length outside of the passed boundary +range+. 80 # If the length is above the boundary, the too_long_msg message will be used. If below, the too_short_msg.81 def add_on_boundary_breaking(attributes, range, too_long_msg = @@default_error_messages[:too_long], too_short_msg = @@default_error_messages[:too_short])111 # If the length is above the boundary, the too_long_msg_id message will be used. If below, the too_short_msg_id 112 def add_on_boundary_breaking(attributes, range, too_long_msg_id = :too_long, too_short_msg_id = :too_short) 82 113 for attr in [attributes].flatten 83 114 value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] 84 add(attr, too_short_msg %range.begin) if value && value.length < range.begin85 add(attr, too_long_msg %range.end) if value && value.length > range.end115 add(attr, too_short_msg_id, range.begin) if value && value.length < range.begin 116 add(attr, too_long_msg_id, range.end) if value && value.length > range.end 86 117 end 87 118 end 88 119 … … 142 173 # name - can't be blank 143 174 # address - can't be blank 144 175 def each 145 @errors.each _key { |attr| @errors[attr].each { |msg| yield attr, msg} }176 @errors.each { |attr,errors| errors.each { |error| yield attr, error } } 146 177 end 147 178 148 179 # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned … … 159 190 # Name can't be blank 160 191 # Address can't be blank 161 192 def each_full 162 full_messages.each { |m sg| yield msg}193 full_messages.each { |message| yield message } 163 194 end 164 195 165 196 # Returns all the full error messages in an array. … … 175 206 def full_messages 176 207 full_messages = [] 177 208 178 @errors.each _key do |attr|179 @errors[attr].each do |msg|180 next if msg.nil?209 @errors.each do |attr,errors| 210 errors.each do |error| 211 next if error.nil? 181 212 182 213 if attr == "base" 183 full_messages << msg214 full_messages << error.message 184 215 else 185 full_messages << @base.class.human_attribute_name(attr) + " " + msg216 full_messages << @base.class.human_attribute_name(attr) + " " + error.message 186 217 end 187 218 end 188 219 end … … 391 422 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 392 423 # method, proc or string should return or evaluate to a true or false value. 393 424 def validates_confirmation_of(*attr_names) 394 configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }425 configuration = { :message => :confirmation, :on => :save } 395 426 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 396 427 397 428 attr_accessor *(attr_names.map { |n| "#{n}_confirmation" }) … … 420 451 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 421 452 # method, proc or string should return or evaluate to a true or false value. 422 453 def validates_acceptance_of(*attr_names) 423 configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" }454 configuration = { :message => :accepted, :on => :save, :allow_nil => true, :accept => "1" } 424 455 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 425 456 426 457 attr_accessor *attr_names … … 461 492 # failures on saves when both the parent object and the child object are 462 493 # new. 463 494 def validates_presence_of(*attr_names) 464 configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save }495 configuration = { :message => :blank, :on => :save } 465 496 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 466 497 467 498 # can't use validates_each here, because it cannot cope with nonexistent attributes, … … 505 536 def validates_length_of(*attrs) 506 537 # Merge given options with defaults. 507 538 options = { 508 :too_long => ActiveRecord::Errors.default_error_messages[:too_long],509 :too_short => ActiveRecord::Errors.default_error_messages[:too_short],510 :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]539 :too_long => :too_long, 540 :too_short => :too_short, 541 :wrong_length => :wrong_length 511 542 }.merge(DEFAULT_VALIDATION_OPTIONS) 512 543 options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash) 513 544 … … 530 561 when :within, :in 531 562 raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) 532 563 533 too_short = options[:too_short] % option_value.begin534 too_long = options[:too_long] % option_value.end564 too_short = [options[:too_short], option_value.begin] 565 too_long = [options[:too_long], option_value.end] 535 566 536 567 validates_each(attrs, options) do |record, attr, value| 537 568 if value.nil? or value.split(//).size < option_value.begin 538 record.errors.add(attr, too_short)569 record.errors.add(attr, *too_short) 539 570 elsif value.split(//).size > option_value.end 540 record.errors.add(attr, too_long)571 record.errors.add(attr, *too_long) 541 572 end 542 573 end 543 574 when :is, :minimum, :maximum … … 547 578 validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } 548 579 message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } 549 580 550 message = (options[:message] || options[message_options[option]]) % option_value581 message = [(options[:message] || options[message_options[option]]), option_value] 551 582 552 583 validates_each(attrs, options) do |record, attr, value| 553 584 if value.kind_of?(String) 554 record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]585 record.errors.add(attr, *message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] 555 586 else 556 record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]587 record.errors.add(attr, *message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] 557 588 end 558 589 end 559 590 end … … 588 619 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 589 620 # method, proc or string should return or evaluate to a true or false value. 590 621 def validates_uniqueness_of(*attr_names) 591 configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true }622 configuration = { :message => :taken, :case_sensitive => true } 592 623 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 593 624 594 625 validates_each(attr_names,configuration) do |record, attr_name, value| … … 636 667 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 637 668 # method, proc or string should return or evaluate to a true or false value. 638 669 def validates_format_of(*attr_names) 639 configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }670 configuration = { :message => :invalid, :on => :save, :with => nil } 640 671 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 641 672 642 673 raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp) … … 661 692 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 662 693 # method, proc or string should return or evaluate to a true or false value. 663 694 def validates_inclusion_of(*attr_names) 664 configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }695 configuration = { :message => :inclusion, :on => :save } 665 696 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 666 697 667 698 enum = configuration[:in] || configuration[:within] … … 688 719 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 689 720 # method, proc or string should return or evaluate to a true or false value. 690 721 def validates_exclusion_of(*attr_names) 691 configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save }722 configuration = { :message => :exclusion, :on => :save } 692 723 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 693 724 694 725 enum = configuration[:in] || configuration[:within] … … 728 759 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 729 760 # method, proc or string should return or evaluate to a true or false value. 730 761 def validates_associated(*attr_names) 731 configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }762 configuration = { :message => :invalid, :on => :save } 732 763 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 733 764 734 765 validates_each(attr_names, configuration) do |record, attr_name, value| … … 754 785 # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The 755 786 # method, proc or string should return or evaluate to a true or false value. 756 787 def validates_numericality_of(*attr_names) 757 configuration = { :message => ActiveRecord::Errors.default_error_messages[:not_a_number], :on => :save,788 configuration = { :message => :not_a_number, :on => :save, 758 789 :only_integer => false, :allow_nil => false } 759 790 configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 760 791 -
activerecord/test/validations_test.rb
old new 30 30 Topic.write_inheritable_attribute(:validate_on_update, nil) 31 31 end 32 32 33 def test_comparsion_with_msg_id 34 Topic.validates_presence_of :title 35 t = Topic.new 36 assert !t.valid? 37 assert_equal :blank, t.errors.on(:title) 38 end 39 40 def test_error_message_to_string_message 41 Topic.validates_presence_of :title 42 t = Topic.new 43 assert !t.valid? 44 assert_equal "can't be blank", t.errors.on(:title).to_s 45 end 46 33 47 def test_single_field_validation 34 48 r = Reply.new 35 49 r.title = "There's no content!"