Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ActiveRecord] upsert not updating updated_at when no changes #51771

Open
morganchristiansson opened this issue May 8, 2024 · 1 comment
Open
Labels
more-information-needed When reporter needs to provide more information

Comments

@morganchristiansson
Copy link

morganchristiansson commented May 8, 2024

Steps to reproduce

require 'bundler/inline'

gemfile(true) do
  source "https://rubygems.org"

  gem 'rails', '7.1.3.2'
  gem 'sqlite3', '~> 1.4.0'
end

require 'active_record'
require 'minitest/autorun'
require 'logger'

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :keys, force: true do |t|
    t.string :key, null: false
    t.index :key, unique: true
    t.timestamps
  end
end

class Key < ActiveRecord::Base
end

class BugTest < Minitest::Test
  OLD_TIME = 1.day.ago.beginning_of_day
  def setup
    Key.destroy_all
    s = Key.create(key: 'abc')
    s.update_attribute :updated_at, OLD_TIME
  end

  #FAILS
  def test_upsert
    Key.upsert({key: 'abc'}, unique_by: :key)
    assert OLD_TIME != Key.first.updated_at, 'expected updated_at to change'
  end

  #WORKS due to update of column that is not in unique_by
  def test_upsert_with_change
    Key.upsert({key: 'abc', created_at: Time.now}, unique_by: :key)
    assert OLD_TIME != Key.first.updated_at, 'expected updated_at to change'
  end
end

Expected behavior

I'm using #upsert to touch records by key and set updated_at.

upsert should update updated_at column.

Actual behavior

ON CONFLICT ("key") DO NOTHING is used and upsert does not update updated_at.

Logs:

Key Insert (0.1ms)  INSERT INTO "keys" ("key","created_at","updated_at")
                    VALUES ('abc', STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'), STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'))
                    ON CONFLICT ("key") DO NOTHING RETURNING "id"

System configuration

Rails version: 7.3.2.1
Ruby version: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]

@pokonski
Copy link
Contributor

pokonski commented May 9, 2024

Rails version: 7.3.2.1

I assume you mean 7.1.3.2?

Anyway, this is configurable, see the docs: https://api.rubyonrails.org/classes/ActiveRecord/Persistence/ClassMethods.html#method-i-upsert_all

you can use on_duplicate to define the desired behaviour instead of DO NOTHING

@zzak zzak added the more-information-needed When reporter needs to provide more information label May 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
more-information-needed When reporter needs to provide more information
Projects
None yet
Development

No branches or pull requests

3 participants