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.rb4
-rw-r--r--activemodel/lib/active_model/dirty.rb1
-rw-r--r--activemodel/lib/active_model/errors.rb8
-rw-r--r--activemodel/lib/active_model/lint.rb28
-rw-r--r--activemodel/lib/active_model/secure_password.rb58
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb1
-rw-r--r--activemodel/lib/active_model/validations.rb12
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb2
-rw-r--r--activemodel/lib/active_model/validations/validates.rb8
9 files changed, 101 insertions, 21 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index c1c5640616..fc5f5c4c66 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -46,8 +46,8 @@ module ActiveModel
# end
# end
#
- # Notice that whenever you include ActiveModel::AttributeMethods in your class,
- # it requires you to implement a <tt>attributes</tt> methods which returns a hash
+ # Note that whenever you include ActiveModel::AttributeMethods in your class,
+ # it requires you to implement an <tt>attributes</tt> method which returns a hash
# with each attribute name in your model as hash key and the attribute value as
# hash value.
#
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 1dfd0b6132..a479795d51 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -1,5 +1,4 @@
require 'active_model/attribute_methods'
-require 'active_support/concern'
require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/object/duplicable'
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 99f47f2cbe..fdca852c7a 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -165,7 +165,13 @@ module ActiveModel
# Returns an ActiveSupport::OrderedHash that can be used as the JSON representation for this object.
def as_json(options=nil)
- self
+ to_hash
+ end
+
+ def to_hash
+ hash = ActiveSupport::OrderedHash.new
+ each { |k, v| (hash[k] ||= []) << v }
+ hash
end
# Adds +message+ to the error messages on +attribute+, which will be returned on a call to
diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb
index d7a6da48ca..957d1b9d70 100644
--- a/activemodel/lib/active_model/lint.rb
+++ b/activemodel/lib/active_model/lint.rb
@@ -1,19 +1,19 @@
-# == Active Model Lint Tests
-#
-# You can test whether an object is compliant with the Active Model API by
-# including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will include
-# tests that tell you whether your object is fully compliant, or if not,
-# which aspects of the API are not implemented.
-#
-# These tests do not attempt to determine the semantic correctness of the
-# returned values. For instance, you could implement valid? to always
-# return true, and the tests would pass. It is up to you to ensure that
-# the values are semantically meaningful.
-#
-# Objects you pass in are expected to return a compliant object from a
-# call to to_model. It is perfectly fine for to_model to return self.
module ActiveModel
module Lint
+ # == Active Model Lint Tests
+ #
+ # You can test whether an object is compliant with the Active Model API by
+ # including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will include
+ # tests that tell you whether your object is fully compliant, or if not,
+ # which aspects of the API are not implemented.
+ #
+ # These tests do not attempt to determine the semantic correctness of the
+ # returned values. For instance, you could implement valid? to always
+ # return true, and the tests would pass. It is up to you to ensure that
+ # the values are semantically meaningful.
+ #
+ # Objects you pass in are expected to return a compliant object from a
+ # call to to_model. It is perfectly fine for to_model to return self.
module Tests
# == Responds to <tt>to_key</tt>
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
new file mode 100644
index 0000000000..52941942b8
--- /dev/null
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -0,0 +1,58 @@
+require 'bcrypt'
+
+module ActiveModel
+ module SecurePassword
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ # Adds methods to set and authenticate against a BCrypt password.
+ # This mechanism requires you to have a password_digest attribute.
+ #
+ # Validations for presence of password, confirmation of password (using
+ # a "password_confirmation" attribute) are automatically added.
+ # You can add more validations by hand if need be.
+ #
+ # Example using Active Record (which automatically includes ActiveModel::SecurePassword):
+ #
+ # # Schema: User(name:string, password_digest:string)
+ # class User < ActiveRecord::Base
+ # has_secure_password
+ # end
+ #
+ # user = User.new(:name => "david", :password => "", :password_confirmation => "nomatch")
+ # user.save # => false, password required
+ # user.password = "mUc3m00RsqyRe"
+ # user.save # => false, confirmation doesn't match
+ # user.password_confirmation = "mUc3m00RsqyRe"
+ # user.save # => true
+ # user.authenticate("notright") # => false
+ # user.authenticate("mUc3m00RsqyRe") # => user
+ # User.find_by_name("david").try(:authenticate, "notright") # => nil
+ # User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user
+ def has_secure_password
+ 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
+ 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
+ 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)
+ end
+ end
+end
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index 26a134568c..b897baa614 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -17,6 +17,7 @@ module ActiveModel
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
+ raw_value = raw_value.in_time_zone if raw_value.respond_to?(:in_time_zone)
@value = raw_value || @serializable.send(name)
@type = compute_type
end
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index b044caa8d3..6cb015a144 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -104,7 +104,7 @@ module ActiveModel
# end
# end
#
- # Or with a block which is passed with the current record to be validated:
+ # With a block which is passed with the current record to be validated:
#
# class Comment
# include ActiveModel::Validations
@@ -118,6 +118,16 @@ module ActiveModel
# end
# end
#
+ # Or with a block where self points to the current record to be validated:
+ #
+ # class Comment
+ # include ActiveModel::Validations
+ #
+ # validate do
+ # errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
+ # end
+ # end
+ #
def validate(*args, &block)
options = args.extract_options!
if options.key?(:on)
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index b6aff7aa6b..95fe20de75 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -24,7 +24,7 @@ module ActiveModel
def validate_each(record, attr_name, value)
before_type_cast = "#{attr_name}_before_type_cast"
- raw_value = record.send("#{attr_name}_before_type_cast") if record.respond_to?(before_type_cast.to_sym)
+ raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym)
raw_value ||= value
return if options[:allow_nil] && raw_value.nil?
diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb
index 77c5073c6e..0132f68282 100644
--- a/activemodel/lib/active_model/validations/validates.rb
+++ b/activemodel/lib/active_model/validations/validates.rb
@@ -55,6 +55,10 @@ module ActiveModel
# validates :name, :title => true
# end
#
+ # Additionally validator classes may be in another namespace and still used within any class.
+ #
+ # validates :name, :'file/title' => true
+ #
# The validators hash can also handle regular expressions, ranges,
# arrays and strings in shortcut form, e.g.
#
@@ -86,8 +90,10 @@ module ActiveModel
defaults.merge!(:attributes => attributes)
validations.each do |key, options|
+ key = "#{key.to_s.camelize}Validator"
+
begin
- validator = const_get("#{key.to_s.camelize}Validator")
+ validator = key.include?('::') ? key.constantize : const_get(key)
rescue NameError
raise ArgumentError, "Unknown validator: '#{key}'"
end