2017-07-09 13:41:28 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-06 12:26:20 -04:00
|
|
|
require "cases/helper"
|
|
|
|
require "support/ddl_helper"
|
|
|
|
require "models/developer"
|
|
|
|
require "models/computer"
|
|
|
|
require "models/owner"
|
|
|
|
require "models/pet"
|
|
|
|
require "models/toy"
|
|
|
|
require "models/car"
|
|
|
|
require "models/task"
|
2009-04-16 17:48:07 -04:00
|
|
|
|
|
|
|
class TimestampTest < ActiveRecord::TestCase
|
2010-09-24 13:35:35 -04:00
|
|
|
fixtures :developers, :owners, :pets, :toys, :cars, :tasks
|
2009-04-16 17:48:07 -04:00
|
|
|
|
|
|
|
def setup
|
|
|
|
@developer = Developer.first
|
2013-11-05 07:44:16 -05:00
|
|
|
@owner = Owner.first
|
2012-07-24 19:20:03 -04:00
|
|
|
@developer.update_columns(updated_at: Time.now.prev_month)
|
2009-04-16 17:48:07 -04:00
|
|
|
@previously_updated_at = @developer.updated_at
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_saving_a_changed_record_updates_its_timestamp
|
|
|
|
@developer.name = "Jack Bauer"
|
|
|
|
@developer.save!
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_not_equal @previously_updated_at, @developer.updated_at
|
2009-04-16 17:48:07 -04:00
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2009-04-16 17:48:07 -04:00
|
|
|
def test_saving_a_unchanged_record_doesnt_update_its_timestamp
|
|
|
|
@developer.save!
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_equal @previously_updated_at, @developer.updated_at
|
2009-04-16 17:48:07 -04:00
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2009-04-16 17:48:07 -04:00
|
|
|
def test_touching_a_record_updates_its_timestamp
|
2010-07-09 14:11:51 -04:00
|
|
|
previous_salary = @developer.salary
|
|
|
|
@developer.salary = previous_salary + 10000
|
2009-04-16 17:48:07 -04:00
|
|
|
@developer.touch
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_not_equal @previously_updated_at, @developer.updated_at
|
2010-07-09 14:11:51 -04:00
|
|
|
assert_equal previous_salary + 10000, @developer.salary
|
2016-08-06 12:26:20 -04:00
|
|
|
assert @developer.salary_changed?, "developer salary should have changed"
|
|
|
|
assert @developer.changed?, "developer should be marked as changed"
|
2010-07-09 14:11:51 -04:00
|
|
|
@developer.reload
|
|
|
|
assert_equal previous_salary, @developer.salary
|
2009-04-16 17:48:07 -04:00
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2011-06-07 17:21:05 -04:00
|
|
|
def test_touching_a_record_with_default_scope_that_excludes_it_updates_its_timestamp
|
2011-06-06 03:30:05 -04:00
|
|
|
developer = @developer.becomes(DeveloperCalledJamis)
|
|
|
|
|
|
|
|
developer.touch
|
|
|
|
assert_not_equal @previously_updated_at, developer.updated_at
|
|
|
|
developer.reload
|
|
|
|
assert_not_equal @previously_updated_at, developer.updated_at
|
|
|
|
end
|
|
|
|
|
2010-08-24 09:20:02 -04:00
|
|
|
def test_saving_when_record_timestamps_is_false_doesnt_update_its_timestamp
|
|
|
|
Developer.record_timestamps = false
|
|
|
|
@developer.name = "John Smith"
|
|
|
|
@developer.save!
|
|
|
|
|
|
|
|
assert_equal @previously_updated_at, @developer.updated_at
|
|
|
|
ensure
|
|
|
|
Developer.record_timestamps = true
|
|
|
|
end
|
|
|
|
|
2011-10-26 13:20:12 -04:00
|
|
|
def test_saving_when_instance_record_timestamps_is_false_doesnt_update_its_timestamp
|
|
|
|
@developer.record_timestamps = false
|
|
|
|
assert Developer.record_timestamps
|
|
|
|
|
|
|
|
@developer.name = "John Smith"
|
|
|
|
@developer.save!
|
|
|
|
|
|
|
|
assert_equal @previously_updated_at, @developer.updated_at
|
|
|
|
end
|
|
|
|
|
2015-02-16 01:30:41 -05:00
|
|
|
def test_touching_updates_timestamp_with_given_time
|
2016-08-06 13:55:02 -04:00
|
|
|
previously_updated_at = @developer.updated_at
|
|
|
|
new_time = Time.utc(2015, 2, 16, 0, 0, 0)
|
|
|
|
@developer.touch(time: new_time)
|
2015-02-16 01:30:41 -05:00
|
|
|
|
2016-08-06 13:55:02 -04:00
|
|
|
assert_not_equal previously_updated_at, @developer.updated_at
|
|
|
|
assert_equal new_time, @developer.updated_at
|
2015-02-16 01:30:41 -05:00
|
|
|
end
|
|
|
|
|
2010-09-24 13:35:35 -04:00
|
|
|
def test_touching_an_attribute_updates_timestamp
|
2009-04-16 18:25:55 -04:00
|
|
|
previously_created_at = @developer.created_at
|
2015-09-23 11:43:19 -04:00
|
|
|
travel(1.second) do
|
|
|
|
@developer.touch(:created_at)
|
|
|
|
end
|
2009-04-16 18:25:55 -04:00
|
|
|
|
2018-05-12 22:26:10 -04:00
|
|
|
assert_not @developer.created_at_changed?, "created_at should not be changed"
|
|
|
|
assert_not @developer.changed?, "record should not be changed"
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_not_equal previously_created_at, @developer.created_at
|
2010-07-09 14:11:51 -04:00
|
|
|
assert_not_equal @previously_updated_at, @developer.updated_at
|
2009-04-16 18:25:55 -04:00
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2018-03-22 21:05:54 -04:00
|
|
|
def test_touching_update_at_attribute_as_symbol_updates_timestamp
|
|
|
|
travel(1.second) do
|
|
|
|
@developer.touch(:updated_at)
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_not @developer.updated_at_changed?
|
|
|
|
assert_not @developer.changed?
|
|
|
|
assert_not_equal @previously_updated_at, @developer.updated_at
|
|
|
|
end
|
|
|
|
|
2010-09-24 13:35:35 -04:00
|
|
|
def test_touching_an_attribute_updates_it
|
|
|
|
task = Task.first
|
|
|
|
previous_value = task.ending
|
|
|
|
task.touch(:ending)
|
2016-02-06 06:01:00 -05:00
|
|
|
|
|
|
|
now = Time.now.change(usec: 0)
|
|
|
|
|
2010-09-24 13:35:35 -04:00
|
|
|
assert_not_equal previous_value, task.ending
|
2016-02-06 06:01:00 -05:00
|
|
|
assert_in_delta now, task.ending, 1
|
2010-09-24 13:35:35 -04:00
|
|
|
end
|
|
|
|
|
2015-02-16 01:30:41 -05:00
|
|
|
def test_touching_an_attribute_updates_timestamp_with_given_time
|
2016-08-06 13:55:02 -04:00
|
|
|
previously_updated_at = @developer.updated_at
|
2015-02-16 01:30:41 -05:00
|
|
|
previously_created_at = @developer.created_at
|
2016-08-06 13:55:02 -04:00
|
|
|
new_time = Time.utc(2015, 2, 16, 4, 54, 0)
|
2015-02-16 01:30:41 -05:00
|
|
|
@developer.touch(:created_at, time: new_time)
|
|
|
|
|
|
|
|
assert_not_equal previously_created_at, @developer.created_at
|
|
|
|
assert_not_equal previously_updated_at, @developer.updated_at
|
|
|
|
assert_equal new_time, @developer.created_at
|
|
|
|
assert_equal new_time, @developer.updated_at
|
|
|
|
end
|
|
|
|
|
2014-03-19 21:13:03 -04:00
|
|
|
def test_touching_many_attributes_updates_them
|
|
|
|
task = Task.first
|
|
|
|
previous_starting = task.starting
|
|
|
|
previous_ending = task.ending
|
|
|
|
task.touch(:starting, :ending)
|
2014-04-23 00:37:13 -04:00
|
|
|
|
2016-02-06 06:01:00 -05:00
|
|
|
now = Time.now.change(usec: 0)
|
|
|
|
|
2014-03-19 21:13:03 -04:00
|
|
|
assert_not_equal previous_starting, task.starting
|
|
|
|
assert_not_equal previous_ending, task.ending
|
2016-02-06 06:01:00 -05:00
|
|
|
assert_in_delta now, task.starting, 1
|
|
|
|
assert_in_delta now, task.ending, 1
|
2014-03-19 21:13:03 -04:00
|
|
|
end
|
|
|
|
|
2010-09-24 13:35:35 -04:00
|
|
|
def test_touching_a_record_without_timestamps_is_unexceptional
|
|
|
|
assert_nothing_raised { Car.first.touch }
|
2010-08-24 09:56:26 -04:00
|
|
|
end
|
|
|
|
|
2013-11-05 07:44:16 -05:00
|
|
|
def test_touching_a_no_touching_object
|
|
|
|
Developer.no_touching do
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @developer, :no_touching?
|
|
|
|
assert_not_predicate @owner, :no_touching?
|
2013-11-05 07:44:16 -05:00
|
|
|
@developer.touch
|
|
|
|
end
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_not_predicate @developer, :no_touching?
|
|
|
|
assert_not_predicate @owner, :no_touching?
|
2013-11-05 07:44:16 -05:00
|
|
|
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
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @developer, :no_touching?
|
|
|
|
assert_predicate @owner, :no_touching?
|
2013-11-05 07:44:16 -05:00
|
|
|
@developer.touch
|
|
|
|
end
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_not_predicate @developer, :no_touching?
|
|
|
|
assert_not_predicate @owner, :no_touching?
|
2013-11-05 07:44:16 -05:00
|
|
|
assert_equal @previously_updated_at, @developer.updated_at
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_no_touching_threadsafe
|
|
|
|
Thread.new do
|
|
|
|
Developer.no_touching do
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @developer, :no_touching?
|
2013-11-05 07:44:16 -05:00
|
|
|
|
|
|
|
sleep(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_not_predicate @developer, :no_touching?
|
2013-11-05 07:44:16 -05:00
|
|
|
end
|
|
|
|
|
2014-04-23 00:37:13 -04:00
|
|
|
def test_no_touching_with_callbacks
|
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
|
|
self.table_name = "developers"
|
|
|
|
|
|
|
|
attr_accessor :after_touch_called
|
|
|
|
|
|
|
|
after_touch do |user|
|
|
|
|
user.after_touch_called = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
developer = klass.first
|
|
|
|
|
|
|
|
klass.no_touching do
|
|
|
|
developer.touch
|
|
|
|
assert_not developer.after_touch_called
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-04-16 18:25:55 -04:00
|
|
|
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
|
|
|
|
previously_owner_updated_at = owner.updated_at
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2015-09-23 11:43:19 -04:00
|
|
|
travel(1.second) do
|
|
|
|
pet.name = "Fluffy the Third"
|
|
|
|
pet.save
|
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_not_equal previously_owner_updated_at, pet.owner.updated_at
|
2009-04-16 18:25:55 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_destroying_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at
|
|
|
|
pet = Pet.first
|
|
|
|
owner = pet.owner
|
|
|
|
previously_owner_updated_at = owner.updated_at
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2015-09-23 11:43:19 -04:00
|
|
|
travel(1.second) do
|
|
|
|
pet.destroy
|
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_not_equal previously_owner_updated_at, pet.owner.updated_at
|
2009-04-16 18:25:55 -04:00
|
|
|
end
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2013-02-26 10:55:18 -05:00
|
|
|
def test_saving_a_new_record_belonging_to_invalid_parent_with_touch_should_not_raise_exception
|
|
|
|
klass = Class.new(Owner) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Owner"; end
|
2013-02-26 10:55:18 -05:00
|
|
|
validate { errors.add(:base, :invalid) }
|
|
|
|
end
|
|
|
|
|
|
|
|
pet = Pet.new(owner: klass.new)
|
|
|
|
pet.save!
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate pet.owner, :new_record?
|
2013-02-26 10:55:18 -05:00
|
|
|
end
|
|
|
|
|
2009-04-16 18:25:55 -04:00
|
|
|
def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute
|
2012-08-10 12:42:48 -04:00
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Pet"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
belongs_to :owner, touch: :happy_at
|
2012-08-10 12:42:48 -04:00
|
|
|
end
|
2009-04-16 18:25:55 -04:00
|
|
|
|
2012-08-10 12:42:48 -04:00
|
|
|
pet = klass.first
|
2009-04-16 18:25:55 -04:00
|
|
|
owner = pet.owner
|
|
|
|
previously_owner_happy_at = owner.happy_at
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2009-04-16 18:25:55 -04:00
|
|
|
pet.name = "Fluffy the Third"
|
|
|
|
pet.save
|
2010-08-14 01:13:00 -04:00
|
|
|
|
2010-05-19 15:14:51 -04:00
|
|
|
assert_not_equal previously_owner_happy_at, pet.owner.happy_at
|
2009-04-16 18:25:55 -04:00
|
|
|
end
|
2010-08-02 05:07:43 -04:00
|
|
|
|
2010-08-12 12:43:15 -04:00
|
|
|
def test_touching_a_record_with_a_belongs_to_that_uses_a_counter_cache_should_update_the_parent
|
2012-08-10 12:42:48 -04:00
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Pet"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
belongs_to :owner, counter_cache: :use_count, touch: true
|
2012-08-10 12:42:48 -04:00
|
|
|
end
|
2010-08-12 12:43:15 -04:00
|
|
|
|
2012-08-10 12:42:48 -04:00
|
|
|
pet = klass.first
|
2010-08-12 12:43:15 -04:00
|
|
|
owner = pet.owner
|
2012-07-24 19:20:03 -04:00
|
|
|
owner.update_columns(happy_at: 3.days.ago)
|
2010-08-12 12:43:15 -04:00
|
|
|
previously_owner_updated_at = owner.updated_at
|
|
|
|
|
2015-09-23 11:43:19 -04:00
|
|
|
travel(1.second) do
|
|
|
|
pet.name = "I'm a parrot"
|
|
|
|
pet.save
|
|
|
|
end
|
2010-08-12 12:43:15 -04:00
|
|
|
|
|
|
|
assert_not_equal previously_owner_updated_at, pet.owner.updated_at
|
|
|
|
end
|
|
|
|
|
2010-08-02 05:07:43 -04:00
|
|
|
def test_touching_a_record_touches_parent_record_and_grandparent_record
|
2012-08-10 12:42:48 -04:00
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Toy"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
belongs_to :pet, touch: true
|
2012-08-10 12:42:48 -04:00
|
|
|
end
|
2010-08-02 05:07:43 -04:00
|
|
|
|
2012-08-10 12:42:48 -04:00
|
|
|
toy = klass.first
|
2010-08-02 05:07:43 -04:00
|
|
|
pet = toy.pet
|
|
|
|
owner = pet.owner
|
2011-03-27 18:12:28 -04:00
|
|
|
time = 3.days.ago
|
2010-08-02 05:07:43 -04:00
|
|
|
|
2012-07-24 19:20:03 -04:00
|
|
|
owner.update_columns(updated_at: time)
|
2010-08-02 05:07:43 -04:00
|
|
|
toy.touch
|
2010-08-02 18:10:34 -04:00
|
|
|
owner.reload
|
2010-08-02 05:07:43 -04:00
|
|
|
|
2010-08-02 10:16:02 -04:00
|
|
|
assert_not_equal time, owner.updated_at
|
2010-08-02 05:07:43 -04:00
|
|
|
end
|
2011-01-25 17:20:57 -05:00
|
|
|
|
2013-04-22 21:08:44 -04:00
|
|
|
def test_touching_a_record_touches_polymorphic_record
|
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Toy"; end
|
2013-04-22 21:08:44 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
wheel_klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Wheel"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
belongs_to :wheelable, polymorphic: true, touch: true
|
2013-04-22 21:08:44 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
toy = klass.first
|
|
|
|
time = 3.days.ago
|
|
|
|
toy.update_columns(updated_at: time)
|
|
|
|
|
|
|
|
wheel = wheel_klass.new
|
|
|
|
wheel.wheelable = toy
|
|
|
|
wheel.save
|
|
|
|
wheel.touch
|
|
|
|
|
|
|
|
assert_not_equal time, toy.updated_at
|
|
|
|
end
|
|
|
|
|
2013-04-24 08:37:33 -04:00
|
|
|
def test_changing_parent_of_a_record_touches_both_new_and_old_parent_record
|
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Toy"; end
|
2013-04-24 08:37:33 -04:00
|
|
|
belongs_to :pet, touch: true
|
|
|
|
end
|
|
|
|
|
|
|
|
toy1 = klass.find(1)
|
|
|
|
old_pet = toy1.pet
|
|
|
|
|
|
|
|
toy2 = klass.find(2)
|
|
|
|
new_pet = toy2.pet
|
|
|
|
time = 3.days.ago.at_beginning_of_hour
|
|
|
|
|
|
|
|
old_pet.update_columns(updated_at: time)
|
|
|
|
new_pet.update_columns(updated_at: time)
|
|
|
|
|
|
|
|
toy1.pet = new_pet
|
|
|
|
toy1.save!
|
|
|
|
|
|
|
|
old_pet.reload
|
|
|
|
new_pet.reload
|
|
|
|
|
|
|
|
assert_not_equal time, new_pet.updated_at
|
|
|
|
assert_not_equal time, old_pet.updated_at
|
|
|
|
end
|
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record_changes_within_same_class
|
|
|
|
car_class = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Car"; end
|
2013-04-22 21:08:44 -04:00
|
|
|
end
|
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
wheel_class = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Wheel"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
belongs_to :wheelable, polymorphic: true, touch: true
|
2013-04-22 21:08:44 -04:00
|
|
|
end
|
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
car1 = car_class.find(1)
|
|
|
|
car2 = car_class.find(2)
|
2013-04-22 21:08:44 -04:00
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
wheel = wheel_class.create!(wheelable: car1)
|
2013-04-22 21:08:44 -04:00
|
|
|
|
|
|
|
time = 3.days.ago.at_beginning_of_hour
|
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
car1.update_columns(updated_at: time)
|
|
|
|
car2.update_columns(updated_at: time)
|
2013-04-22 21:08:44 -04:00
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
wheel.wheelable = car2
|
2013-04-22 21:08:44 -04:00
|
|
|
wheel.save!
|
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
assert_not_equal time, car1.reload.updated_at
|
|
|
|
assert_not_equal time, car2.reload.updated_at
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_changing_parent_of_a_record_touches_both_new_and_old_polymorphic_parent_record_changes_with_other_class
|
|
|
|
car_class = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Car"; end
|
2013-12-05 09:57:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
toy_class = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Toy"; end
|
2013-12-05 09:57:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
wheel_class = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Wheel"; end
|
2016-08-06 13:37:57 -04:00
|
|
|
belongs_to :wheelable, polymorphic: true, touch: true
|
2013-12-05 09:57:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
car = car_class.find(1)
|
|
|
|
toy = toy_class.find(3)
|
|
|
|
|
|
|
|
wheel = wheel_class.create!(wheelable: car)
|
|
|
|
|
|
|
|
time = 3.days.ago.at_beginning_of_hour
|
|
|
|
|
|
|
|
car.update_columns(updated_at: time)
|
|
|
|
toy.update_columns(updated_at: time)
|
|
|
|
|
|
|
|
wheel.wheelable = toy
|
|
|
|
wheel.save!
|
2013-04-22 21:08:44 -04:00
|
|
|
|
2013-12-05 09:57:05 -05:00
|
|
|
assert_not_equal time, car.reload.updated_at
|
|
|
|
assert_not_equal time, toy.reload.updated_at
|
2013-04-22 21:08:44 -04:00
|
|
|
end
|
|
|
|
|
2013-04-24 08:37:33 -04:00
|
|
|
def test_clearing_association_touches_the_old_record
|
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
def self.name; "Toy"; end
|
2013-04-24 08:37:33 -04:00
|
|
|
belongs_to :pet, touch: true
|
|
|
|
end
|
|
|
|
|
|
|
|
toy = klass.find(1)
|
|
|
|
pet = toy.pet
|
|
|
|
time = 3.days.ago.at_beginning_of_hour
|
|
|
|
|
|
|
|
pet.update_columns(updated_at: time)
|
|
|
|
|
|
|
|
toy.pet = nil
|
|
|
|
toy.save!
|
|
|
|
|
|
|
|
pet.reload
|
|
|
|
|
|
|
|
assert_not_equal time, pet.updated_at
|
|
|
|
end
|
|
|
|
|
2014-06-09 16:25:20 -04:00
|
|
|
def test_timestamp_column_values_are_present_in_the_callbacks
|
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
2016-08-06 12:26:20 -04:00
|
|
|
self.table_name = "people"
|
2014-06-09 16:25:20 -04:00
|
|
|
|
|
|
|
before_create do
|
2017-01-05 03:20:57 -05:00
|
|
|
self.born_at = created_at
|
2014-06-09 16:25:20 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:26:20 -04:00
|
|
|
person = klass.create first_name: "David"
|
2014-06-09 16:25:20 -04:00
|
|
|
assert_not_equal person.born_at, nil
|
|
|
|
end
|
|
|
|
|
2011-01-25 17:27:27 -05:00
|
|
|
def test_timestamp_attributes_for_create_in_model
|
|
|
|
toy = Toy.first
|
Change `timestamp_attributes_for_{create,update}` from symbol to string
`timestamp_attributes_for_{create,update}` is defined as symbol but
always used as string with `to_s`. This allocates extra strings. To
avoid extra allocation, change the definitions from symbol to string.
```ruby
pp ObjectSpace::AllocationTracer.trace {
1_000.times { |i|
Post.create!
}
}
```
Before:
```
["~/rails/activerecord/lib/active_record/timestamp.rb", 121]=>[1002, 0, 750, 0, 1, 18528],
["~/rails/activerecord/lib/active_record/timestamp.rb", 105]=>[1002, 0, 750, 0, 1, 7720],
["~/rails/activerecord/lib/active_record/timestamp.rb", 101]=>[1002, 0, 750, 0, 1, 7720],
["~/rails/activerecord/lib/active_record/timestamp.rb", 109]=>[1002, 0, 750, 0, 1, 13896],
["~/rails/activerecord/lib/active_record/timestamp.rb", 61]=>[4008, 0, 3000, 0, 1, 30880],
```
After:
```
["~/rails/activerecord/lib/active_record/timestamp.rb", 120]=>[1000, 0, 756, 0, 1, 17184],
["~/rails/activerecord/lib/active_record/timestamp.rb", 104]=>[1000, 0, 756, 0, 1, 7160],
["~/rails/activerecord/lib/active_record/timestamp.rb", 100]=>[1000, 0, 756, 0, 1, 7160],
["~/rails/activerecord/lib/active_record/timestamp.rb", 108]=>[1000, 0, 756, 0, 1, 12888],
```
2016-12-31 16:49:46 -05:00
|
|
|
assert_equal ["created_at"], toy.send(:timestamp_attributes_for_create_in_model)
|
2011-01-25 17:27:27 -05:00
|
|
|
end
|
2011-01-25 17:28:31 -05:00
|
|
|
|
|
|
|
def test_timestamp_attributes_for_update_in_model
|
|
|
|
toy = Toy.first
|
Change `timestamp_attributes_for_{create,update}` from symbol to string
`timestamp_attributes_for_{create,update}` is defined as symbol but
always used as string with `to_s`. This allocates extra strings. To
avoid extra allocation, change the definitions from symbol to string.
```ruby
pp ObjectSpace::AllocationTracer.trace {
1_000.times { |i|
Post.create!
}
}
```
Before:
```
["~/rails/activerecord/lib/active_record/timestamp.rb", 121]=>[1002, 0, 750, 0, 1, 18528],
["~/rails/activerecord/lib/active_record/timestamp.rb", 105]=>[1002, 0, 750, 0, 1, 7720],
["~/rails/activerecord/lib/active_record/timestamp.rb", 101]=>[1002, 0, 750, 0, 1, 7720],
["~/rails/activerecord/lib/active_record/timestamp.rb", 109]=>[1002, 0, 750, 0, 1, 13896],
["~/rails/activerecord/lib/active_record/timestamp.rb", 61]=>[4008, 0, 3000, 0, 1, 30880],
```
After:
```
["~/rails/activerecord/lib/active_record/timestamp.rb", 120]=>[1000, 0, 756, 0, 1, 17184],
["~/rails/activerecord/lib/active_record/timestamp.rb", 104]=>[1000, 0, 756, 0, 1, 7160],
["~/rails/activerecord/lib/active_record/timestamp.rb", 100]=>[1000, 0, 756, 0, 1, 7160],
["~/rails/activerecord/lib/active_record/timestamp.rb", 108]=>[1000, 0, 756, 0, 1, 12888],
```
2016-12-31 16:49:46 -05:00
|
|
|
assert_equal ["updated_at"], toy.send(:timestamp_attributes_for_update_in_model)
|
2011-01-25 17:28:31 -05:00
|
|
|
end
|
2011-01-25 17:33:55 -05:00
|
|
|
|
|
|
|
def test_all_timestamp_attributes_in_model
|
|
|
|
toy = Toy.first
|
Change `timestamp_attributes_for_{create,update}` from symbol to string
`timestamp_attributes_for_{create,update}` is defined as symbol but
always used as string with `to_s`. This allocates extra strings. To
avoid extra allocation, change the definitions from symbol to string.
```ruby
pp ObjectSpace::AllocationTracer.trace {
1_000.times { |i|
Post.create!
}
}
```
Before:
```
["~/rails/activerecord/lib/active_record/timestamp.rb", 121]=>[1002, 0, 750, 0, 1, 18528],
["~/rails/activerecord/lib/active_record/timestamp.rb", 105]=>[1002, 0, 750, 0, 1, 7720],
["~/rails/activerecord/lib/active_record/timestamp.rb", 101]=>[1002, 0, 750, 0, 1, 7720],
["~/rails/activerecord/lib/active_record/timestamp.rb", 109]=>[1002, 0, 750, 0, 1, 13896],
["~/rails/activerecord/lib/active_record/timestamp.rb", 61]=>[4008, 0, 3000, 0, 1, 30880],
```
After:
```
["~/rails/activerecord/lib/active_record/timestamp.rb", 120]=>[1000, 0, 756, 0, 1, 17184],
["~/rails/activerecord/lib/active_record/timestamp.rb", 104]=>[1000, 0, 756, 0, 1, 7160],
["~/rails/activerecord/lib/active_record/timestamp.rb", 100]=>[1000, 0, 756, 0, 1, 7160],
["~/rails/activerecord/lib/active_record/timestamp.rb", 108]=>[1000, 0, 756, 0, 1, 12888],
```
2016-12-31 16:49:46 -05:00
|
|
|
assert_equal ["created_at", "updated_at"], toy.send(:all_timestamp_attributes_in_model)
|
2011-01-25 17:33:55 -05:00
|
|
|
end
|
2010-05-19 15:14:51 -04:00
|
|
|
end
|
2014-08-14 06:11:44 -04:00
|
|
|
|
|
|
|
class TimestampsWithoutTransactionTest < ActiveRecord::TestCase
|
|
|
|
include DdlHelper
|
2015-03-10 22:21:19 -04:00
|
|
|
self.use_transactional_tests = false
|
2014-08-14 06:11:44 -04:00
|
|
|
|
|
|
|
class TimestampAttributePost < ActiveRecord::Base
|
|
|
|
attr_accessor :created_at, :updated_at
|
|
|
|
end
|
2014-02-16 07:40:23 -05:00
|
|
|
|
|
|
|
def test_do_not_write_timestamps_on_save_if_they_are_not_attributes
|
2014-08-14 06:11:44 -04:00
|
|
|
with_example_table ActiveRecord::Base.connection, "timestamp_attribute_posts", "id integer primary key" do
|
|
|
|
post = TimestampAttributePost.new(id: 1)
|
|
|
|
post.save! # should not try to assign and persist created_at, updated_at
|
|
|
|
assert_nil post.created_at
|
|
|
|
assert_nil post.updated_at
|
2014-02-16 07:40:23 -05:00
|
|
|
end
|
|
|
|
end
|
2017-08-17 09:17:49 -04:00
|
|
|
|
|
|
|
def test_index_is_created_for_both_timestamps
|
|
|
|
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
|
|
|
|
t.timestamps null: true, index: true
|
|
|
|
end
|
|
|
|
|
|
|
|
indexes = ActiveRecord::Base.connection.indexes("foos")
|
|
|
|
assert_equal ["created_at", "updated_at"], indexes.flat_map(&:columns).sort
|
|
|
|
ensure
|
|
|
|
ActiveRecord::Base.connection.drop_table(:foos)
|
|
|
|
end
|
2010-05-19 15:14:51 -04:00
|
|
|
end
|