add #no_touching on ActiveRecord models
This commit is contained in:
parent
bba8bb8b40
commit
b32ba367f5
@ -1,3 +1,13 @@
|
||||
* Added `ActiveRecord::Base.no_touching`, which allows ignoring touch on models.
|
||||
|
||||
Examples:
|
||||
|
||||
Post.no_touching do
|
||||
Post.first.touch
|
||||
end
|
||||
|
||||
*Sam Stephenson*, *Damien Mathieu*
|
||||
|
||||
* Prevent the counter cache from being decremented twice when destroying
|
||||
a record on a has_many :through association.
|
||||
|
||||
|
@ -45,6 +45,7 @@ module ActiveRecord
|
||||
autoload :Migrator, 'active_record/migration'
|
||||
autoload :ModelSchema
|
||||
autoload :NestedAttributes
|
||||
autoload :NoTouching
|
||||
autoload :Persistence
|
||||
autoload :QueryCache
|
||||
autoload :Querying
|
||||
|
@ -295,6 +295,7 @@ class Base
|
||||
extend Delegation::DelegateCache
|
||||
|
||||
include Persistence
|
||||
include NoTouching
|
||||
include ReadonlyAttributes
|
||||
include ModelSchema
|
||||
include Inheritance
|
||||
|
52
activerecord/lib/active_record/no_touching.rb
Normal file
52
activerecord/lib/active_record/no_touching.rb
Normal file
@ -0,0 +1,52 @@
|
||||
module ActiveRecord
|
||||
# = Active Record No Touching
|
||||
module NoTouching
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
# Lets you selectively disable calls to `touch` for the
|
||||
# duration of a block.
|
||||
#
|
||||
# ==== Examples
|
||||
# ActiveRecord::Base.no_touching do
|
||||
# Project.first.touch # does nothing
|
||||
# Message.first.touch # does nothing
|
||||
# end
|
||||
#
|
||||
# Project.no_touching do
|
||||
# Project.first.touch # does nothing
|
||||
# Message.first.touch # works, but does not touch the associated project
|
||||
# end
|
||||
#
|
||||
def no_touching(&block)
|
||||
NoTouching.apply_to(self, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def apply_to(klass) #:nodoc:
|
||||
klasses.push(klass)
|
||||
yield
|
||||
ensure
|
||||
klasses.pop
|
||||
end
|
||||
|
||||
def applied_to?(klass) #:nodoc:
|
||||
klasses.any? { |k| k >= klass }
|
||||
end
|
||||
|
||||
private
|
||||
def klasses
|
||||
Thread.current[:no_touching_classes] ||= []
|
||||
end
|
||||
end
|
||||
|
||||
def no_touching?
|
||||
NoTouching.applied_to?(self.class)
|
||||
end
|
||||
|
||||
def touch(*)
|
||||
super unless no_touching?
|
||||
end
|
||||
end
|
||||
end
|
@ -11,6 +11,7 @@ class TimestampTest < ActiveRecord::TestCase
|
||||
|
||||
def setup
|
||||
@developer = Developer.first
|
||||
@owner = Owner.first
|
||||
@developer.update_columns(updated_at: Time.now.prev_month)
|
||||
@previously_updated_at = @developer.updated_at
|
||||
end
|
||||
@ -92,6 +93,53 @@ def test_touching_a_record_without_timestamps_is_unexceptional
|
||||
assert_nothing_raised { Car.first.touch }
|
||||
end
|
||||
|
||||
def test_touching_a_no_touching_object
|
||||
Developer.no_touching do
|
||||
assert @developer.no_touching?
|
||||
assert !@owner.no_touching?
|
||||
@developer.touch
|
||||
end
|
||||
|
||||
assert !@developer.no_touching?
|
||||
assert !@owner.no_touching?
|
||||
assert_equal @previously_updated_at, @developer.updated_at
|
||||
end
|
||||
|
||||
def test_touching_related_objects
|
||||
@owner = Owner.first
|
||||
@previously_updated_at = @owner.updated_at
|
||||
|
||||
Owner.no_touching do
|
||||
@owner.pets.first.touch
|
||||
end
|
||||
|
||||
assert_equal @previously_updated_at, @owner.updated_at
|
||||
end
|
||||
|
||||
def test_global_no_touching
|
||||
ActiveRecord::Base.no_touching do
|
||||
assert @developer.no_touching?
|
||||
assert @owner.no_touching?
|
||||
@developer.touch
|
||||
end
|
||||
|
||||
assert !@developer.no_touching?
|
||||
assert !@owner.no_touching?
|
||||
assert_equal @previously_updated_at, @developer.updated_at
|
||||
end
|
||||
|
||||
def test_no_touching_threadsafe
|
||||
Thread.new do
|
||||
Developer.no_touching do
|
||||
assert @developer.no_touching?
|
||||
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
|
||||
assert !@developer.no_touching?
|
||||
end
|
||||
|
||||
def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at
|
||||
pet = Pet.first
|
||||
owner = pet.owner
|
||||
|
Loading…
Reference in New Issue
Block a user