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/dirty.rb31
-rw-r--r--activemodel/lib/active_model/naming.rb7
-rw-r--r--activemodel/lib/active_model/secure_password.rb2
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb14
4 files changed, 47 insertions, 7 deletions
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 98ffffeb10..dc6088a39a 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -17,6 +17,7 @@ module ActiveModel
# * Call <tt>changes_applied</tt> after the changes are persisted.
# * Call <tt>reset_changes</tt> when you want to reset the changes
# information.
+ # * Call <tt>undo_changes</tt> when you want to restore previous data.
#
# A minimal implementation could be:
#
@@ -42,6 +43,10 @@ module ActiveModel
# def reload!
# reset_changes
# end
+ #
+ # def rollback!
+ # undo_changes
+ # end
# end
#
# A newly instantiated object is unchanged:
@@ -72,6 +77,13 @@ module ActiveModel
# person.reload!
# person.previous_changes # => {}
#
+ # Rollback the changes:
+ #
+ # person.name = "Uncle Bob"
+ # person.rollback!
+ # person.name # => "Bill"
+ # person.name_changed? # => false
+ #
# Assigning the same value leaves the attribute unchanged:
#
# person.name = 'Bill'
@@ -84,9 +96,11 @@ module ActiveModel
# person.changed # => ["name"]
# person.changes # => {"name" => ["Bill", "Bob"]}
#
- # If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
- # to mark that the attribute is changing. Otherwise ActiveModel can't track
- # changes to in-place attributes.
+ # If an attribute is modified in-place then make use of
+ # +[attribute_name]_will_change!+ to mark that the attribute is changing.
+ # Otherwise Active Model can't track changes to in-place attributes. Note
+ # that Active Record can detect in-place modifications automatically. You do
+ # not need to call +[attribute_name]_will_change!+ on Active Record models.
#
# person.name_will_change!
# person.name_change # => ["Bill", "Bill"]
@@ -165,17 +179,22 @@ module ActiveModel
private
# Removes current changes and makes them accessible through +previous_changes+.
- def changes_applied
+ def changes_applied # :doc:
@previously_changed = changes
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end
- # Removes all dirty data: current changes and previous changes
- def reset_changes
+ # Removes all dirty data: current changes and previous changes.
+ def reset_changes # :doc:
@previously_changed = ActiveSupport::HashWithIndifferentAccess.new
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end
+ # Restore all previous data.
+ def undo_changes # :doc:
+ changed_attributes.each_key { |attr| reset_attribute! attr }
+ end
+
# Handle <tt>*_change</tt> for +method_missing+.
def attribute_change(attr)
[changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index 5219de2606..86f5c96af9 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -214,6 +214,13 @@ module ActiveModel
# is required to pass the Active Model Lint test. So either extending the
# provided method below, or rolling your own is required.
module Naming
+ def self.extended(base) #:nodoc:
+ base.class_eval do
+ remove_possible_method(:model_name)
+ delegate :model_name, to: :class
+ end
+ end
+
# Returns an ActiveModel::Name object for module. It can be
# used to retrieve all kinds of naming-related information
# (See ActiveModel::Name for more information).
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index fdfd8cb147..7e179cf4b7 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -64,6 +64,8 @@ module ActiveModel
include InstanceMethodsOnActivation
if options.fetch(:validations, true)
+ include ActiveModel::Validations
+
# This ensures the model has a password by checking whether the password_digest
# is present, so that this works with both new and existing records. However,
# when there is an error, the message is added to the password attribute instead
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index a9fb9804d4..5bd162433d 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -30,7 +30,7 @@ module ActiveModel
return
end
- if options[:only_integer]
+ if allow_only_integer?(record)
unless value = parse_raw_value_as_an_integer(raw_value)
record.errors.add(attr_name, :not_an_integer, filtered_options(raw_value))
return
@@ -75,6 +75,17 @@ module ActiveModel
filtered[:value] = value
filtered
end
+
+ def allow_only_integer?(record)
+ case options[:only_integer]
+ when Symbol
+ record.send(options[:only_integer])
+ when Proc
+ options[:only_integer].call(record)
+ else
+ options[:only_integer]
+ end
+ end
end
module HelperMethods
@@ -121,6 +132,7 @@ module ActiveModel
# * <tt>:equal_to</tt>
# * <tt>:less_than</tt>
# * <tt>:less_than_or_equal_to</tt>
+ # * <tt>:only_integer</tt>
#
# For example:
#