1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/test/cases/timestamp_test.rb
Severin Schoepke f1a646fa74 polymorphic belongs_to association with touch: true updates old record correctly
Example: Given you have a comments model with a polymorphic commentable
association (e.g. books and songs) with the touch option set.
Every time you update a comment its commentable should be touched.
This was working when you changed attributes on the comment or when you
moved the comment from one book to another. However, it was not working
when moving a comment from a book to a song. This is now fixed.
2013-12-05 16:03:07 +01:00

382 lines
10 KiB
Ruby

require 'cases/helper'
require 'models/developer'
require 'models/owner'
require 'models/pet'
require 'models/toy'
require 'models/car'
require 'models/task'
class TimestampTest < ActiveRecord::TestCase
fixtures :developers, :owners, :pets, :toys, :cars, :tasks
def setup
@developer = Developer.first
@owner = Owner.first
@developer.update_columns(updated_at: Time.now.prev_month)
@previously_updated_at = @developer.updated_at
end
def test_saving_a_changed_record_updates_its_timestamp
@developer.name = "Jack Bauer"
@developer.save!
assert_not_equal @previously_updated_at, @developer.updated_at
end
def test_saving_a_unchanged_record_doesnt_update_its_timestamp
@developer.save!
assert_equal @previously_updated_at, @developer.updated_at
end
def test_touching_a_record_updates_its_timestamp
previous_salary = @developer.salary
@developer.salary = previous_salary + 10000
@developer.touch
assert_not_equal @previously_updated_at, @developer.updated_at
assert_equal previous_salary + 10000, @developer.salary
assert @developer.salary_changed?, 'developer salary should have changed'
assert @developer.changed?, 'developer should be marked as changed'
@developer.reload
assert_equal previous_salary, @developer.salary
end
def test_touching_a_record_with_default_scope_that_excludes_it_updates_its_timestamp
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
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
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
def test_touching_an_attribute_updates_timestamp
previously_created_at = @developer.created_at
@developer.touch(:created_at)
assert !@developer.created_at_changed? , 'created_at should not be changed'
assert !@developer.changed?, 'record should not be changed'
assert_not_equal previously_created_at, @developer.created_at
assert_not_equal @previously_updated_at, @developer.updated_at
end
def test_touching_an_attribute_updates_it
task = Task.first
previous_value = task.ending
task.touch(:ending)
assert_not_equal previous_value, task.ending
assert_in_delta Time.now, task.ending, 1
end
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
previously_owner_updated_at = owner.updated_at
pet.name = "Fluffy the Third"
pet.save
assert_not_equal previously_owner_updated_at, pet.owner.updated_at
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
pet.destroy
assert_not_equal previously_owner_updated_at, pet.owner.updated_at
end
def test_saving_a_new_record_belonging_to_invalid_parent_with_touch_should_not_raise_exception
klass = Class.new(Owner) do
def self.name; 'Owner'; end
validate { errors.add(:base, :invalid) }
end
pet = Pet.new(owner: klass.new)
pet.save!
assert pet.owner.new_record?
end
def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute
klass = Class.new(ActiveRecord::Base) do
def self.name; 'Pet'; end
belongs_to :owner, :touch => :happy_at
end
pet = klass.first
owner = pet.owner
previously_owner_happy_at = owner.happy_at
pet.name = "Fluffy the Third"
pet.save
assert_not_equal previously_owner_happy_at, pet.owner.happy_at
end
def test_touching_a_record_with_a_belongs_to_that_uses_a_counter_cache_should_update_the_parent
klass = Class.new(ActiveRecord::Base) do
def self.name; 'Pet'; end
belongs_to :owner, :counter_cache => :use_count, :touch => true
end
pet = klass.first
owner = pet.owner
owner.update_columns(happy_at: 3.days.ago)
previously_owner_updated_at = owner.updated_at
pet.name = "I'm a parrot"
pet.save
assert_not_equal previously_owner_updated_at, pet.owner.updated_at
end
def test_touching_a_record_touches_parent_record_and_grandparent_record
klass = Class.new(ActiveRecord::Base) do
def self.name; 'Toy'; end
belongs_to :pet, :touch => true
end
toy = klass.first
pet = toy.pet
owner = pet.owner
time = 3.days.ago
owner.update_columns(updated_at: time)
toy.touch
owner.reload
assert_not_equal time, owner.updated_at
end
def test_touching_a_record_touches_polymorphic_record
klass = Class.new(ActiveRecord::Base) do
def self.name; 'Toy'; end
end
wheel_klass = Class.new(ActiveRecord::Base) do
def self.name; 'Wheel'; end
belongs_to :wheelable, :polymorphic => true, :touch => true
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
def test_changing_parent_of_a_record_touches_both_new_and_old_parent_record
klass = Class.new(ActiveRecord::Base) do
def self.name; 'Toy'; end
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
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
def self.name; 'Car'; end
end
wheel_class = Class.new(ActiveRecord::Base) do
def self.name; 'Wheel'; end
belongs_to :wheelable, :polymorphic => true, :touch => true
end
car1 = car_class.find(1)
car2 = car_class.find(2)
wheel = wheel_class.create!(wheelable: car1)
time = 3.days.ago.at_beginning_of_hour
car1.update_columns(updated_at: time)
car2.update_columns(updated_at: time)
wheel.wheelable = car2
wheel.save!
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
def self.name; 'Car'; end
end
toy_class = Class.new(ActiveRecord::Base) do
def self.name; 'Toy'; end
end
wheel_class = Class.new(ActiveRecord::Base) do
def self.name; 'Wheel'; end
belongs_to :wheelable, :polymorphic => true, :touch => true
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!
assert_not_equal time, car.reload.updated_at
assert_not_equal time, toy.reload.updated_at
end
def test_clearing_association_touches_the_old_record
klass = Class.new(ActiveRecord::Base) do
def self.name; 'Toy'; end
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
def test_timestamp_attributes_for_create
toy = Toy.first
assert_equal [:created_at, :created_on], toy.send(:timestamp_attributes_for_create)
end
def test_timestamp_attributes_for_update
toy = Toy.first
assert_equal [:updated_at, :updated_on], toy.send(:timestamp_attributes_for_update)
end
def test_all_timestamp_attributes
toy = Toy.first
assert_equal [:created_at, :created_on, :updated_at, :updated_on], toy.send(:all_timestamp_attributes)
end
def test_timestamp_attributes_for_create_in_model
toy = Toy.first
assert_equal [:created_at], toy.send(:timestamp_attributes_for_create_in_model)
end
def test_timestamp_attributes_for_update_in_model
toy = Toy.first
assert_equal [:updated_at], toy.send(:timestamp_attributes_for_update_in_model)
end
def test_all_timestamp_attributes_in_model
toy = Toy.first
assert_equal [:created_at, :updated_at], toy.send(:all_timestamp_attributes_in_model)
end
end