class DirtyTest

Public Instance Methods

catchphrase() click to toggle source
Calls superclass method
# File activerecord/test/cases/dirty_test.rb, line 672
def catchphrase
  super.upcase
end
setup() click to toggle source

Dummy to force column loads so query counts are clean.

# File activerecord/test/cases/dirty_test.rb, line 15
def setup
  Person.create first_name: "foo"
end
test_aliased_attribute_changes() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 136
def test_aliased_attribute_changes
  # the actual attribute here is name, title is an
  # alias setup via alias_attribute
  parrot = Parrot.new
  assert !parrot.title_changed?
  assert_nil parrot.title_change

  parrot.name = "Sam"
  assert parrot.title_changed?
  assert_nil parrot.title_was
  assert_equal parrot.name_change, parrot.title_change
end
test_association_assignment_changes_foreign_key() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 309
def test_association_assignment_changes_foreign_key
  pirate = Pirate.create!(catchphrase: "jarl")
  pirate.parrot = Parrot.create!(name: "Lorre")
  assert pirate.changed?
  assert_equal %w(parrot_id), pirate.changed
end
test_attribute_changes() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 19
def test_attribute_changes
  # New record - no changes.
  pirate = Pirate.new
  assert_equal false, pirate.catchphrase_changed?
  assert_equal false, pirate.non_validated_parrot_id_changed?

  # Change catchphrase.
  pirate.catchphrase = "arrr"
  assert pirate.catchphrase_changed?
  assert_nil pirate.catchphrase_was
  assert_equal [nil, "arrr"], pirate.catchphrase_change

  # Saved - no changes.
  pirate.save!
  assert !pirate.catchphrase_changed?
  assert_nil pirate.catchphrase_change

  # Same value - no changes.
  pirate.catchphrase = "arrr"
  assert !pirate.catchphrase_changed?
  assert_nil pirate.catchphrase_change
end
test_attribute_should_be_compared_with_type_cast() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 316
def test_attribute_should_be_compared_with_type_cast
  topic = Topic.new
  assert topic.approved?
  assert !topic.approved_changed?

  # Coming from web form.
  params = { topic: { approved: 1 } }
  # In the controller.
  topic.attributes = params[:topic]
  assert topic.approved?
  assert !topic.approved_changed?
end
test_attribute_will_change!() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 290
def test_attribute_will_change!
  pirate = Pirate.create!(catchphrase: "arr")

  assert !pirate.catchphrase_changed?
  assert pirate.catchphrase_will_change!
  assert pirate.catchphrase_changed?
  assert_equal ["arr", "arr"], pirate.catchphrase_change

  pirate.catchphrase << " matey!"
  assert pirate.catchphrase_changed?
  assert_equal ["arr", "arr matey!"], pirate.catchphrase_change
end
test_changed_attributes_should_be_preserved_if_save_failure() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 366
def test_changed_attributes_should_be_preserved_if_save_failure
  pirate = Pirate.new
  pirate.parrot_id = 1
  assert !pirate.save
  check_pirate_after_save_failure(pirate)

  pirate = Pirate.new
  pirate.parrot_id = 1
  assert_raise(ActiveRecord::RecordInvalid) { pirate.save! }
  check_pirate_after_save_failure(pirate)
end
test_datetime_attribute_can_be_updated_with_fractional_seconds() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 579
def test_datetime_attribute_can_be_updated_with_fractional_seconds
  skip "Fractional seconds are not supported" unless subsecond_precision_supported?
  in_time_zone "Paris" do
    target = Class.new(ActiveRecord::Base)
    target.table_name = "topics"

    written_on = Time.utc(2012, 12, 1, 12, 0, 0).in_time_zone("Paris")

    topic = target.create(written_on: written_on)
    topic.written_on += 0.3

    assert topic.written_on_changed?, "Fractional second update not detected"
  end
end
test_datetime_attribute_doesnt_change_if_zone_is_modified_in_string() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 594
def test_datetime_attribute_doesnt_change_if_zone_is_modified_in_string
  time_in_paris = Time.utc(2014, 1, 1, 12, 0, 0).in_time_zone("Paris")
  pirate = Pirate.create!(catchphrase: "rrrr", created_on: time_in_paris)

  pirate.created_on = pirate.created_on.in_time_zone("Tokyo").to_s
  assert !pirate.created_on_changed?
end
test_dup_objects_should_not_copy_dirty_flag_from_creator() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 386
def test_dup_objects_should_not_copy_dirty_flag_from_creator
  pirate = Pirate.create!(catchphrase: "shiver me timbers")
  pirate_dup = pirate.dup
  pirate_dup.restore_catchphrase!
  pirate.catchphrase = "I love Rum"
  assert pirate.catchphrase_changed?
  assert !pirate_dup.catchphrase_changed?
end
test_field_named_field() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 567
def test_field_named_field
  ActiveRecord::Base.connection.create_table :testings do |t|
    t.string :field
  end
  assert_nothing_raised do
    Testings.new.attributes
  end
ensure
  ActiveRecord::Base.connection.drop_table :testings rescue nil
  ActiveRecord::Base.clear_cache!
end
test_float_zero_to_string_zero_not_marked_as_changed() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 229
def test_float_zero_to_string_zero_not_marked_as_changed
  data = NumericData.new temperature: 0.0
  data.save!

  assert_not data.changed?

  data.temperature = "0"
  assert_empty data.changes

  data.temperature = "0.0"
  assert_empty data.changes

  data.temperature = "0.00"
  assert_empty data.changes
end
test_integer_zero_to_integer_zero_not_marked_as_changed() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 217
def test_integer_zero_to_integer_zero_not_marked_as_changed
  pirate = Pirate.new
  pirate.parrot_id = 0
  pirate.catchphrase = "arrr"
  assert pirate.save!

  assert !pirate.changed?

  pirate.parrot_id = 0
  assert !pirate.changed?
end
test_integer_zero_to_string_zero_not_marked_as_changed() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 205
def test_integer_zero_to_string_zero_not_marked_as_changed
  pirate = Pirate.new
  pirate.parrot_id = 0
  pirate.catchphrase = "arrr"
  assert pirate.save!

  assert !pirate.changed?

  pirate.parrot_id = "0"
  assert !pirate.changed?
end
test_nullable_datetime_not_marked_as_changed_if_new_value_is_blank() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 189
def test_nullable_datetime_not_marked_as_changed_if_new_value_is_blank
  in_time_zone "Edinburgh" do
    target = Class.new(ActiveRecord::Base)
    target.table_name = "topics"

    topic = target.create
    assert_nil topic.written_on

    ["", nil].each do |value|
      topic.written_on = value
      assert_nil topic.written_on
      assert !topic.written_on_changed?
    end
  end
end
test_nullable_decimal_not_marked_as_changed_if_new_value_is_blank() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 169
def test_nullable_decimal_not_marked_as_changed_if_new_value_is_blank
  numeric_data = NumericData.new

  ["", nil].each do |value|
    numeric_data.bank_balance = value
    assert !numeric_data.bank_balance_changed?
    assert_nil numeric_data.bank_balance_change
  end
end
test_nullable_float_not_marked_as_changed_if_new_value_is_blank() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 179
def test_nullable_float_not_marked_as_changed_if_new_value_is_blank
  numeric_data = NumericData.new

  ["", nil].each do |value|
    numeric_data.temperature = value
    assert !numeric_data.temperature_changed?
    assert_nil numeric_data.temperature_change
  end
end
test_nullable_number_not_marked_as_changed_if_new_value_is_blank() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 159
def test_nullable_number_not_marked_as_changed_if_new_value_is_blank
  pirate = Pirate.new

  ["", nil].each do |value|
    pirate.parrot_id = value
    assert !pirate.parrot_id_changed?
    assert_nil pirate.parrot_id_change
  end
end
test_object_should_be_changed_if_any_attribute_is_changed() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 272
def test_object_should_be_changed_if_any_attribute_is_changed
  pirate = Pirate.new
  assert !pirate.changed?
  assert_equal [], pirate.changed
  assert_equal Hash.new, pirate.changes

  pirate.catchphrase = "arrr"
  assert pirate.changed?
  assert_nil pirate.catchphrase_was
  assert_equal %w(catchphrase), pirate.changed
  assert_equal({ "catchphrase" => [nil, "arrr"] }, pirate.changes)

  pirate.save
  assert !pirate.changed?
  assert_equal [], pirate.changed
  assert_equal Hash.new, pirate.changes
end
test_partial_update() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 329
def test_partial_update
  pirate = Pirate.new(catchphrase: "foo")
  old_updated_on = 1.hour.ago.beginning_of_day

  with_partial_writes Pirate, false do
    assert_queries(2) { 2.times { pirate.save! } }
    Pirate.where(id: pirate.id).update_all(updated_on: old_updated_on)
  end

  with_partial_writes Pirate, true do
    assert_queries(0) { 2.times { pirate.save! } }
    assert_equal old_updated_on, pirate.reload.updated_on

    assert_queries(1) { pirate.catchphrase = "bar"; pirate.save! }
    assert_not_equal old_updated_on, pirate.reload.updated_on
  end
end
test_partial_update_with_optimistic_locking() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 347
def test_partial_update_with_optimistic_locking
  person = Person.new(first_name: "foo")

  with_partial_writes Person, false do
    assert_queries(2) { 2.times { person.save! } }
    Person.where(id: person.id).update_all(first_name: "baz")
  end

  old_lock_version = person.lock_version

  with_partial_writes Person, true do
    assert_queries(0) { 2.times { person.save! } }
    assert_equal old_lock_version, person.reload.lock_version

    assert_queries(1) { person.first_name = "bar"; person.save! }
    assert_not_equal old_lock_version, person.reload.lock_version
  end
end
test_previous_changes() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 476
def test_previous_changes
  # original values should be in previous_changes
  pirate = Pirate.new

  assert_equal Hash.new, pirate.previous_changes
  pirate.catchphrase = "arrr"
  pirate.save!

  assert_equal 4, pirate.previous_changes.size
  assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"]
  assert_equal [nil, pirate.id], pirate.previous_changes["id"]
  assert_nil pirate.previous_changes["updated_on"][0]
  assert_not_nil pirate.previous_changes["updated_on"][1]
  assert_nil pirate.previous_changes["created_on"][0]
  assert_not_nil pirate.previous_changes["created_on"][1]
  assert !pirate.previous_changes.key?("parrot_id")

  # original values should be in previous_changes
  pirate = Pirate.new

  assert_equal Hash.new, pirate.previous_changes
  pirate.catchphrase = "arrr"
  pirate.save

  assert_equal 4, pirate.previous_changes.size
  assert_equal [nil, "arrr"], pirate.previous_changes["catchphrase"]
  assert_equal [nil, pirate.id], pirate.previous_changes["id"]
  assert_includes pirate.previous_changes, "updated_on"
  assert_includes pirate.previous_changes, "created_on"
  assert !pirate.previous_changes.key?("parrot_id")

  pirate.catchphrase = "Yar!!"
  pirate.reload
  assert_equal Hash.new, pirate.previous_changes

  pirate = Pirate.find_by_catchphrase("arrr")

  travel(1.second)

  pirate.catchphrase = "Me Maties!"
  pirate.save!

  assert_equal 2, pirate.previous_changes.size
  assert_equal ["arrr", "Me Maties!"], pirate.previous_changes["catchphrase"]
  assert_not_nil pirate.previous_changes["updated_on"][0]
  assert_not_nil pirate.previous_changes["updated_on"][1]
  assert !pirate.previous_changes.key?("parrot_id")
  assert !pirate.previous_changes.key?("created_on")

  pirate = Pirate.find_by_catchphrase("Me Maties!")

  travel(1.second)

  pirate.catchphrase = "Thar She Blows!"
  pirate.save

  assert_equal 2, pirate.previous_changes.size
  assert_equal ["Me Maties!", "Thar She Blows!"], pirate.previous_changes["catchphrase"]
  assert_not_nil pirate.previous_changes["updated_on"][0]
  assert_not_nil pirate.previous_changes["updated_on"][1]
  assert !pirate.previous_changes.key?("parrot_id")
  assert !pirate.previous_changes.key?("created_on")

  travel(1.second)

  pirate = Pirate.find_by_catchphrase("Thar She Blows!")
  pirate.update(catchphrase: "Ahoy!")

  assert_equal 2, pirate.previous_changes.size
  assert_equal ["Thar She Blows!", "Ahoy!"], pirate.previous_changes["catchphrase"]
  assert_not_nil pirate.previous_changes["updated_on"][0]
  assert_not_nil pirate.previous_changes["updated_on"][1]
  assert !pirate.previous_changes.key?("parrot_id")
  assert !pirate.previous_changes.key?("created_on")

  travel(1.second)

  pirate = Pirate.find_by_catchphrase("Ahoy!")
  pirate.update_attribute(:catchphrase, "Ninjas suck!")

  assert_equal 2, pirate.previous_changes.size
  assert_equal ["Ahoy!", "Ninjas suck!"], pirate.previous_changes["catchphrase"]
  assert_not_nil pirate.previous_changes["updated_on"][0]
  assert_not_nil pirate.previous_changes["updated_on"][1]
  assert !pirate.previous_changes.key?("parrot_id")
  assert !pirate.previous_changes.key?("created_on")
ensure
  travel_back
end
test_reload_should_clear_changed_attributes() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 378
def test_reload_should_clear_changed_attributes
  pirate = Pirate.create!(catchphrase: "shiver me timbers")
  pirate.catchphrase = "*hic*"
  assert pirate.changed?
  pirate.reload
  assert !pirate.changed?
end
test_restore_attribute!() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 149
def test_restore_attribute!
  pirate = Pirate.create!(catchphrase: "Yar!")
  pirate.catchphrase = "Ahoy!"

  pirate.restore_catchphrase!
  assert_equal "Yar!", pirate.catchphrase
  assert_equal Hash.new, pirate.changes
  assert !pirate.catchphrase_changed?
end
test_reverted_changes_are_not_dirty() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 395
def test_reverted_changes_are_not_dirty
  phrase = "shiver me timbers"
  pirate = Pirate.create!(catchphrase: phrase)
  pirate.catchphrase = "*hic*"
  assert pirate.changed?
  pirate.catchphrase = phrase
  assert !pirate.changed?
end
test_reverted_changes_are_not_dirty_after_multiple_changes() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 404
def test_reverted_changes_are_not_dirty_after_multiple_changes
  phrase = "shiver me timbers"
  pirate = Pirate.create!(catchphrase: phrase)
  10.times do |i|
    pirate.catchphrase = "*hic*" * i
    assert pirate.changed?
  end
  assert pirate.changed?
  pirate.catchphrase = phrase
  assert !pirate.changed?
end
test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 416
def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back
  pirate = Pirate.create!(catchphrase: "Yar!")

  pirate.parrot_id = 1
  assert pirate.changed?
  assert pirate.parrot_id_changed?
  assert !pirate.catchphrase_changed?

  pirate.parrot_id = nil
  assert !pirate.changed?
  assert !pirate.parrot_id_changed?
  assert !pirate.catchphrase_changed?
end
test_save_always_should_update_timestamps_when_serialized_attributes_are_present() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 451
def test_save_always_should_update_timestamps_when_serialized_attributes_are_present
  with_partial_writes(Topic) do
    topic = Topic.create!(content: { a: "a" })
    topic.save!

    updated_at = topic.updated_at
    travel(1.second) do
      topic.content[:hello] = "world"
      topic.save!
    end

    assert_not_equal updated_at, topic.updated_at
    assert_equal "world", topic.content[:hello]
  end
end
test_save_should_not_save_serialized_attribute_with_partial_writes_if_not_present() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 467
def test_save_should_not_save_serialized_attribute_with_partial_writes_if_not_present
  with_partial_writes(Topic) do
    topic = Topic.create!(author_name: "Bill", content: { a: "a" })
    topic = Topic.select("id, author_name").find(topic.id)
    topic.update_columns author_name: "John"
    assert_not_nil topic.reload.content
  end
end
test_save_should_store_serialized_attributes_even_with_partial_writes() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 430
def test_save_should_store_serialized_attributes_even_with_partial_writes
  with_partial_writes(Topic) do
    topic = Topic.create!(content: { a: "a" })

    assert_not topic.changed?

    topic.content[:b] = "b"

    assert topic.changed?

    topic.save!

    assert_not topic.changed?
    assert_equal "b", topic.content[:b]

    topic.reload

    assert_equal "b", topic.content[:b]
  end
end
test_setting_time_attributes_with_time_zone_field_to_itself_should_not_be_marked_as_a_change() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 69
def test_setting_time_attributes_with_time_zone_field_to_itself_should_not_be_marked_as_a_change
  in_time_zone "Paris" do
    target = Class.new(ActiveRecord::Base)
    target.table_name = "pirates"

    pirate = target.create!
    pirate.created_on = pirate.created_on
    assert !pirate.created_on_changed?
  end
end
test_time_attributes_changes_with_time_zone() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 42
def test_time_attributes_changes_with_time_zone
  in_time_zone "Paris" do
    target = Class.new(ActiveRecord::Base)
    target.table_name = "pirates"

    # New record - no changes.
    pirate = target.new
    assert !pirate.created_on_changed?
    assert_nil pirate.created_on_change

    # Saved - no changes.
    pirate.catchphrase = "arrrr, time zone!!"
    pirate.save!
    assert !pirate.created_on_changed?
    assert_nil pirate.created_on_change

    # Change created_on.
    old_created_on = pirate.created_on
    pirate.created_on = Time.now - 1.day
    assert pirate.created_on_changed?
    assert_kind_of ActiveSupport::TimeWithZone, pirate.created_on_was
    assert_equal old_created_on, pirate.created_on_was
    pirate.created_on = old_created_on
    assert !pirate.created_on_changed?
  end
end
test_time_attributes_changes_without_time_zone() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 109
def test_time_attributes_changes_without_time_zone
  with_timezone_config aware_attributes: false do
    target = Class.new(ActiveRecord::Base)
    target.table_name = "pirates"

    # New record - no changes.
    pirate = target.new
    assert !pirate.created_on_changed?
    assert_nil pirate.created_on_change

    # Saved - no changes.
    pirate.catchphrase = "arrrr, time zone!!"
    pirate.save!
    assert !pirate.created_on_changed?
    assert_nil pirate.created_on_change

    # Change created_on.
    old_created_on = pirate.created_on
    pirate.created_on = Time.now + 1.day
    assert pirate.created_on_changed?
    # kind_of does not work because
    # ActiveSupport::TimeWithZone.name == 'Time'
    assert_instance_of Time, pirate.created_on_was
    assert_equal old_created_on, pirate.created_on_was
  end
end
test_time_attributes_changes_without_time_zone_by_skip() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 80
def test_time_attributes_changes_without_time_zone_by_skip
  in_time_zone "Paris" do
    target = Class.new(ActiveRecord::Base)
    target.table_name = "pirates"

    target.skip_time_zone_conversion_for_attributes = [:created_on]

    # New record - no changes.
    pirate = target.new
    assert !pirate.created_on_changed?
    assert_nil pirate.created_on_change

    # Saved - no changes.
    pirate.catchphrase = "arrrr, time zone!!"
    pirate.save!
    assert !pirate.created_on_changed?
    assert_nil pirate.created_on_change

    # Change created_on.
    old_created_on = pirate.created_on
    pirate.created_on = Time.now + 1.day
    assert pirate.created_on_changed?
    # kind_of does not work because
    # ActiveSupport::TimeWithZone.name == 'Time'
    assert_instance_of Time, pirate.created_on_was
    assert_equal old_created_on, pirate.created_on_was
  end
end
test_virtual_attribute_will_change() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 303
def test_virtual_attribute_will_change
  parrot = Parrot.create!(name: "Ruby")
  parrot.send(:attribute_will_change!, :cancel_save_from_callback)
  assert parrot.has_changes_to_save?
end
test_zero_to_blank_marked_as_changed() click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 245
def test_zero_to_blank_marked_as_changed
  pirate = Pirate.new
  pirate.catchphrase = "Yarrrr, me hearties"
  pirate.parrot_id = 1
  pirate.save

  # check the change from 1 to ''
  pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
  pirate.parrot_id = ""
  assert pirate.parrot_id_changed?
  assert_equal([1, nil], pirate.parrot_id_change)
  pirate.save

  # check the change from nil to 0
  pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
  pirate.parrot_id = 0
  assert pirate.parrot_id_changed?
  assert_equal([nil, 0], pirate.parrot_id_change)
  pirate.save

  # check the change from 0 to ''
  pirate = Pirate.find_by_catchphrase("Yarrrr, me hearties")
  pirate.parrot_id = ""
  assert pirate.parrot_id_changed?
  assert_equal([0, nil], pirate.parrot_id_change)
end

Private Instance Methods

check_pirate_after_save_failure(pirate) click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 865
def check_pirate_after_save_failure(pirate)
  assert pirate.changed?
  assert pirate.parrot_id_changed?
  assert_equal %w(parrot_id), pirate.changed
  assert_nil pirate.parrot_id_was
end
with_partial_writes(klass, on = true) { || ... } click to toggle source
# File activerecord/test/cases/dirty_test.rb, line 857
def with_partial_writes(klass, on = true)
  old = klass.partial_writes?
  klass.partial_writes = on
  yield
ensure
  klass.partial_writes = old
end