aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/lib')
-rw-r--r--activemodel/lib/active_model/errors.rb69
-rw-r--r--activemodel/lib/active_model/secure_password.rb8
-rw-r--r--activemodel/lib/active_model/serialization.rb4
-rw-r--r--activemodel/lib/active_model/validations.rb6
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb23
-rw-r--r--activemodel/lib/active_model/validations/validates.rb11
-rw-r--r--activemodel/lib/active_model/validations/with.rb12
7 files changed, 98 insertions, 35 deletions
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 0dc10e3c7d..5e3cf510b0 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -60,9 +60,13 @@ module ActiveModel
# p.validate! # => ["can not be nil"]
# p.errors.full_messages # => ["name can not be nil"]
# # etc..
- class Errors < ActiveSupport::OrderedHash
+ class Errors
+ include Enumerable
+
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank]
+ attr_reader :messages
+
# Pass in the instance of the object that is using the errors object.
#
# class Person
@@ -71,12 +75,29 @@ module ActiveModel
# end
# end
def initialize(base)
- @base = base
- super()
+ @base = base
+ @messages = ActiveSupport::OrderedHash.new
end
- alias_method :get, :[]
- alias_method :set, :[]=
+ # Clear the messages
+ def clear
+ messages.clear
+ end
+
+ # Do the error messages include an error with key +error+?
+ def include?(error)
+ messages.include? error
+ end
+
+ # Get messages for +key+
+ def get(key)
+ messages[key]
+ end
+
+ # Set messages for +key+ to +value+
+ def set(key, value)
+ messages[key] = value
+ end
# When passed a symbol or a name of a method, returns an array of errors
# for the method.
@@ -110,7 +131,7 @@ module ActiveModel
# # then yield :name and "must be specified"
# end
def each
- each_key do |attribute|
+ messages.each_key do |attribute|
self[attribute].each { |error| yield attribute, error }
end
end
@@ -125,6 +146,16 @@ module ActiveModel
values.flatten.size
end
+ # Returns all message values
+ def values
+ messages.values
+ end
+
+ # Returns all message keys
+ def keys
+ messages.keys
+ end
+
# Returns an array of error messages, with the attribute name included
#
# p.errors.add(:name, "can't be blank")
@@ -169,9 +200,7 @@ module ActiveModel
end
def to_hash
- hash = ActiveSupport::OrderedHash.new
- each { |k, v| (hash[k] ||= []) << v }
- hash
+ messages.dup
end
# Adds +message+ to the error messages on +attribute+, which will be returned on a call to
@@ -221,26 +250,20 @@ module ActiveModel
# company.errors.full_messages # =>
# ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"]
def full_messages
- full_messages = []
-
- each do |attribute, messages|
- messages = Array.wrap(messages)
- next if messages.empty?
-
+ map { |attribute, message|
if attribute == :base
- messages.each {|m| full_messages << m }
+ message
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
+ I18n.t(:"errors.format", {
+ :default => "%{attribute} %{message}",
+ :attribute => attr_name,
+ :message => message
+ })
end
- end
-
- full_messages
+ }
end
# Translates an error message in its default scope
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 7e8370a04c..957d0ddaaa 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -33,12 +33,16 @@ module ActiveModel
attr_reader :password
attr_accessor :password_confirmation
- attr_protected(:password_digest) if respond_to?(:attr_protected)
-
validates_confirmation_of :password
validates_presence_of :password_digest
include InstanceMethodsOnActivation
+
+ if respond_to?(:attributes_protected_by_default)
+ def self.attributes_protected_by_default
+ super + ['password_digest']
+ end
+ end
end
end
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index f659419293..caf44a2ee0 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -15,7 +15,7 @@ module ActiveModel
# attr_accessor :name
#
# def attributes
- # @attributes ||= {'name' => nil}
+ # {'name' => name}
# end
#
# end
@@ -45,7 +45,7 @@ module ActiveModel
# attr_accessor :name
#
# def attributes
- # @attributes ||= {'name' => nil}
+ # {'name' => name}
# end
#
# end
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index cdf23c7b1b..efd071fedc 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -146,8 +146,10 @@ module ActiveModel
end
# List all validators that being used to validate a specific attribute.
- def validators_on(attribute)
- _validators[attribute.to_sym]
+ def validators_on(*attributes)
+ attributes.map do |attribute|
+ _validators[attribute.to_sym]
+ end.flatten
end
# Check if method is an attribute method or not.
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index 049b093618..108586b8df 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -8,9 +8,26 @@ module ActiveModel
":in option of the configuration hash" unless options[:in].respond_to?(:include?)
end
- def validate_each(record, attribute, value)
- unless options[:in].include?(value)
- record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
+ # On Ruby 1.9 Range#include? checks all possible values in the range for equality,
+ # so it may be slow for large ranges. The new Range#cover? uses the previous logic
+ # of comparing a value with the range endpoints.
+ if (1..2).respond_to?(:cover?)
+ def validate_each(record, attribute, value)
+ included = if options[:in].is_a?(Range)
+ options[:in].cover?(value)
+ else
+ options[:in].include?(value)
+ end
+
+ unless included
+ record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
+ end
+ end
+ else
+ def validate_each(record, attribute, value)
+ unless options[:in].include?(value)
+ record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value))
+ end
end
end
end
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 0132f68282..7ff42de00b 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -81,10 +81,9 @@ module ActiveModel
#
def validates(*attributes)
defaults = attributes.extract_options!
- validations = defaults.slice!(:if, :unless, :on, :allow_blank, :allow_nil)
+ validations = defaults.slice!(*_validates_default_keys)
raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
- raise ArgumentError, "Attribute names must be symbols" if attributes.any?{ |attribute| !attribute.is_a?(Symbol) }
raise ArgumentError, "You need to supply at least one validation" if validations.empty?
defaults.merge!(:attributes => attributes)
@@ -104,6 +103,12 @@ module ActiveModel
protected
+ # When creating custom validators, it might be useful to be able to specify
+ # additional default keys. This can be done by overwriting this method.
+ def _validates_default_keys
+ [ :if, :unless, :on, :allow_blank, :allow_nil ]
+ end
+
def _parse_validates_options(options) #:nodoc:
case options
when TrueClass
@@ -118,4 +123,4 @@ module ActiveModel
end
end
end
-end \ No newline at end of file
+end
diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb
index 200efd4eb5..1663697727 100644
--- a/activemodel/lib/active_model/validations/with.rb
+++ b/activemodel/lib/active_model/validations/with.rb
@@ -8,6 +8,18 @@ module ActiveModel
end
end
+ class WithValidator < EachValidator
+ def validate_each(record, attr, val)
+ method_name = options[:with]
+
+ if record.method(method_name).arity == 0
+ record.send method_name
+ else
+ record.send method_name, attr
+ end
+ end
+ end
+
module ClassMethods
# Passes the record off to the class or classes specified and allows them
# to add errors based on more complex conditions.