📌

ActiveRecordのupdateの処理追跡班

に公開

「ActiveRecordのupdate処理って、update前と同じ値にupdateする時って、SQL発行されるのかな〜」という疑問から、update処理を追ってみました。

以下のようなパターンです。

tag = Tag.find(1)
  Tag Load (0.9ms)  SELECT "tags".* FROM "tags" WHERE "tags"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
# => #<Tag:0x0000ffff8cbe4240 id: 1, name: "Romance">
tag = Tag.find(1).update(name: "Romance") # 全く同じ名前に更新する

AIに聞いたらすぐ答え返ってきたのですが、嘘つかれたので、たまには自分でコードリーディングをしてみます。

ちなみに、、GTPとGeminiどちらかが嘘つきです。

  • GPT-4.5(o4)

はい、ActiveRecord の update は「同じ値」であっても基本的には SQL を発行します(=UPDATE文が実行されます)。

  • Gemini 2.5 Flash

いいえ、ActiveRecord の update メソッド(および update_attributes)は、update の前と同じ値に更新しようとしても、通常は SQL (UPDATE クエリ) は発行されません

ActiveRecord::Base

  • 各モデルクラス < ApplicationRecord < ActiveRecord::Base
    ActiveRecord::Baseによって、各モデルクラスをActiveRecordたらしめています。
    各テーブルのデータをオブジェクトとして扱うことができるようになります。

  • ActiveRecord::Base

  • しかし、このクラスにはupdateメソッドはありません。includeしている別moduleを探します〜

ActiveRecord::Persistence

  • ActiveRecord::Baseがincludeしているmodule
    永続化関係(saveとかupdateとか)の機能を持つモジュールのようです(多分)
  • update発見
    activerecord/lib/active_record/persistence.rb, line 563
      def update(attributes)
        # The following transaction covers any possible database side-effects of the
        # attributes assignment. For example, setting the IDs of a child collection.
        with_transaction_returning_status do
          assign_attributes(attributes)
          save
        end
      end
    

ActiveRecord::AttributeMethods::Dirty

  • ActiveRecord::BaseがincludeするActiveRecord::AttributeMethodsがincludeしているmodule

  • Active Record modelsの変更をトラッキングする機能を持つ
    dirty(汚れ) = データベースのデータからの変更

  • 属性設定時に発火するらしい(追えてない...)

    • save時にDirty が登録されている属性のみ UPDATE 対象になる -> 値に変化がある場合のみ、UPDATEのSQLが発行される

結論

  • ActiveRecordのupdate処理って、update前と同じ値にupdateする時って、SQL発行されない
  • Geminiは真実を語っていた。chatGPTには嘘つかれた。
  • 検証
TODO: あとで記載

まとめ

  • 結局コードリーディングにはAI頼りました。includeされているmoduleとかを自分で追うのが辛すぎた
  • しかし、安直にAIを信じない方がいい。信頼できるか確認しながら対話するのがよい。

Discussion