aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/lib/active_model')
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb22
-rw-r--r--activemodel/lib/active_model/callbacks.rb7
-rw-r--r--activemodel/lib/active_model/errors.rb71
-rw-r--r--activemodel/lib/active_model/mass_assignment_security.rb38
-rw-r--r--activemodel/lib/active_model/observing.rb10
-rw-r--r--activemodel/lib/active_model/secure_password.rb34
-rw-r--r--activemodel/lib/active_model/serialization.rb4
-rw-r--r--activemodel/lib/active_model/validations.rb8
-rw-r--r--activemodel/lib/active_model/validations/callbacks.rb2
-rw-r--r--activemodel/lib/active_model/validations/validates.rb11
-rw-r--r--activemodel/lib/active_model/validations/with.rb12
11 files changed, 134 insertions, 85 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index fc5f5c4c66..8f3782eb48 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -98,7 +98,7 @@ module ActiveModel
def define_attr_method(name, value=nil, &block)
sing = singleton_class
sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
- if method_defined?(:'original_#{name}')
+ if method_defined?('original_#{name}')
undef :'original_#{name}'
end
alias_method :'original_#{name}', :'#{name}'
@@ -109,7 +109,7 @@ module ActiveModel
# use eval instead of a block to work around a memory leak in dev
# mode in fcgi
sing.class_eval <<-eorb, __FILE__, __LINE__ + 1
- def #{name}; #{value.to_s.inspect}; end
+ def #{name}; #{value.nil? ? 'nil' : value.to_s.inspect}; end
eorb
end
end
@@ -229,15 +229,13 @@ module ActiveModel
def alias_attribute(new_name, old_name)
attribute_method_matchers.each do |matcher|
- module_eval <<-STR, __FILE__, __LINE__ + 1
- def #{matcher.method_name(new_name)}(*args)
- send(:#{matcher.method_name(old_name)}, *args)
- end
- STR
+ define_method(matcher.method_name(new_name)) do |*args|
+ send(matcher.method_name(old_name), *args)
+ end
end
end
- # Declares a the attributes that should be prefixed and suffixed by
+ # Declares the attributes that should be prefixed and suffixed by
# ActiveModel::AttributeMethods.
#
# To use, pass in an array of attribute names (as strings or symbols),
@@ -274,11 +272,11 @@ module ActiveModel
method_name = matcher.method_name(attr_name)
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- if method_defined?(:'#{method_name}')
+ if method_defined?('#{method_name}')
undef :'#{method_name}'
end
- def #{method_name}(*args)
- send(:#{matcher.method_missing_target}, '#{attr_name}', *args)
+ define_method('#{method_name}') do |*args|
+ send('#{matcher.method_missing_target}', '#{attr_name}', *args)
end
STR
end
@@ -325,7 +323,7 @@ module ActiveModel
options.symbolize_keys!
@prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
@regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
- @method_missing_target = :"#{@prefix}attribute#{@suffix}"
+ @method_missing_target = "#{@prefix}attribute#{@suffix}"
@method_name = "#{prefix}%s#{suffix}"
end
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index aaa41f5ec6..2a1f51a9a7 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -24,14 +24,11 @@ module ActiveModel
# you want callbacks on in a block so that the callbacks get a chance to fire:
#
# def create
- # _run_create_callbacks do
+ # run_callbacks :create do
# # Your create action methods here
# end
# end
#
- # The _run_<method_name>_callbacks methods are dynamically created when you extend
- # the <tt>ActiveModel::Callbacks</tt> module.
- #
# Then in your class, you can use the +before_create+, +after_create+ and +around_create+
# methods, just as you would in an Active Record module.
#
@@ -102,7 +99,7 @@ module ActiveModel
define_callbacks(callback, options)
types.each do |type|
- send(:"_define_#{type}_model_callback", self, callback)
+ send("_define_#{type}_model_callback", self, callback)
end
end
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index fdca852c7a..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
+
+ # 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
- alias_method :get, :[]
- alias_method :set, :[]=
+ # 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")
@@ -147,7 +178,7 @@ module ActiveModel
def empty?
all? { |k, v| v && v.empty? }
end
-
+ alias_method :blank?, :empty?
# Returns an xml formatted representation of the Errors hash.
#
# 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/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb
index 66cd9fdde6..97e31d4243 100644
--- a/activemodel/lib/active_model/mass_assignment_security.rb
+++ b/activemodel/lib/active_model/mass_assignment_security.rb
@@ -20,32 +20,32 @@ module ActiveModel
# For example, a logged in user may need to assign additional attributes depending
# on their role:
#
- # class AccountsController < ApplicationController
- # include ActiveModel::MassAssignmentSecurity
+ # class AccountsController < ApplicationController
+ # include ActiveModel::MassAssignmentSecurity
#
- # attr_accessible :first_name, :last_name
+ # attr_accessible :first_name, :last_name
#
- # def self.admin_accessible_attributes
- # accessible_attributes + [ :plan_id ]
- # end
+ # def self.admin_accessible_attributes
+ # accessible_attributes + [ :plan_id ]
+ # end
#
- # def update
- # ...
- # @account.update_attributes(account_params)
- # ...
- # end
+ # def update
+ # ...
+ # @account.update_attributes(account_params)
+ # ...
+ # end
#
- # protected
+ # protected
#
- # def account_params
- # sanitize_for_mass_assignment(params[:account])
- # end
+ # def account_params
+ # sanitize_for_mass_assignment(params[:account])
+ # end
#
- # def mass_assignment_authorizer
- # admin ? admin_accessible_attributes : super
- # end
+ # def mass_assignment_authorizer
+ # admin ? admin_accessible_attributes : super
+ # end
#
- # end
+ # end
#
module ClassMethods
# Attributes named in this macro are protected from mass-assignment
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index 0d2dd36e59..bf4fd0740c 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -13,14 +13,18 @@ module ActiveModel
#
# Activates the observers assigned. Examples:
#
+ # class ORM
+ # include ActiveModel::Observing
+ # end
+ #
# # Calls PersonObserver.instance
- # ActiveRecord::Base.observers = :person_observer
+ # ORM.observers = :person_observer
#
# # Calls Cacher.instance and GarbageCollector.instance
- # ActiveRecord::Base.observers = :cacher, :garbage_collector
+ # ORM.observers = :cacher, :garbage_collector
#
# # Same as above, just using explicit class references
- # ActiveRecord::Base.observers = Cacher, GarbageCollector
+ # ORM.observers = Cacher, GarbageCollector
#
# Note: Setting this does not instantiate the observers yet.
# +instantiate_observers+ is called during startup, and before
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 52941942b8..957d0ddaaa 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -33,26 +33,34 @@ 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
- # Returns self if the password is correct, otherwise false.
- def authenticate(unencrypted_password)
- if BCrypt::Password.new(password_digest) == unencrypted_password
- self
- else
- false
+ module InstanceMethodsOnActivation
+ # Returns self if the password is correct, otherwise false.
+ def authenticate(unencrypted_password)
+ if BCrypt::Password.new(password_digest) == unencrypted_password
+ self
+ else
+ false
+ end
end
- end
- # Encrypts the password into the password_digest attribute.
- def password=(unencrypted_password)
- @password = unencrypted_password
- self.password_digest = BCrypt::Password.create(unencrypted_password)
+ # Encrypts the password into the password_digest attribute.
+ def password=(unencrypted_password)
+ @password = unencrypted_password
+ self.password_digest = BCrypt::Password.create(unencrypted_password)
+ end
end
end
end
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index 37739b98a1..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 6cb015a144..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.
@@ -207,7 +209,7 @@ module ActiveModel
protected
def run_validations!
- _run_validate_callbacks
+ run_callbacks :validate
errors.empty?
end
end
diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb
index 621518de5b..adc2867ad0 100644
--- a/activemodel/lib/active_model/validations/callbacks.rb
+++ b/activemodel/lib/active_model/validations/callbacks.rb
@@ -50,7 +50,7 @@ module ActiveModel
# Overwrite run validations to include callbacks.
def run_validations!
- _run_validation_callbacks { super }
+ run_callbacks(:validation) { super }
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.