---
title: "The Persistence APIs That Skip the Record Lifecycle"
url: https://daily.dev/posts/the-persistence-apis-that-skip-the-record-lifecycle-l3eb62qjm
source_url: https://railsrevelry.substack.com/p/persistence-apis-that-skip-the-record-lifecycle
type: article
source: "RUBYLAND"
published: 2026-08-23T04:58:09.646Z
updated: 2026-08-23T04:58:35.801Z
tags: ["database", "ruby", "rails"]
reading_time: 12
upvotes: 1
comments: 0
language: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The Persistence APIs That Skip the Record Lifecycle

**[RUBYLAND](https://daily.dev/sources/rubyla)** · 12 min read · 1 upvotes · 0 comments

## Summary

Bulk and direct persistence APIs in Active Record such as update_all, delete, delete_all, update_columns, insert_all, and upsert_all bypass parts of the record lifecycle: validations, callbacks, timestamps, and in-memory synchronization. The piece walks through concrete examples showing missing audit rows, stale updated_at values, stale in-memory objects, optimistic-locking StaleObjectError surprises, and skipped normalization on bulk inserts. It closes with a repair pattern that wraps update_all and insert_all! in a transaction with explicit timestamps and audit writes, arguing developers should choose a persistence method based on which lifecycle behaviors the operation actually requires, noting that Rails 8.1 added touch: true support to update_column/update_columns (absent in 8.0 and 7.x).

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://railsrevelry.substack.com/p/persistence-apis-that-skip-the-record-lifecycle>

## Questions this post answers

### Does Rails update_columns support a touch option to update timestamps automatically?

Yes, Rails 8.1 added a touch: true option to both update_column and update_columns, which adds the model's timestamp columns to the direct update call. Without this option, updated_at does not update automatically when using these methods. The option is unavailable in Rails 8.0 and the 7.x series.

_Rails upgraders track version-specific API additions like this on daily.dev before touching production update code._

### Why don't my Active Record callbacks run when I use update_all in Rails?

update_all compiles a single SQL UPDATE statement directly against the database without instantiating any model objects, so there are no records for callbacks, validations, or automatic timestamp updates to run against. It only returns the affected-row count and resets the relation; any Active Record object still in memory continues showing the old attribute values until reloaded.

_daily.dev helps Rails developers debugging lifecycle gaps in bulk persistence methods stay sharp on Active Record internals._

### How is Active Record's delete method different from destroy for removing a record?

delete issues a direct SQL DELETE for the receiver's row and then marks it destroyed and frozen, without running destroy callbacks or honoring dependent association options like dependent: :destroy. destroy instead runs the full destroy callback chain and associated cleanup behavior before removing the row, so a before_destroy callback can even abort the deletion.

_Rails developers choosing between destroy and delete for cleanup logic can dig deeper on daily.dev._

## Similar posts on daily.dev

- [ActiveRecord: Consistent delete\_all and update\_all](https://daily.dev/posts/activerecord-consistent-delete-all-and-update-all-qta6unmqw) · RUBYLAND · 0 upvotes · 0 comments

---

Tags: [#database](https://daily.dev/tags/database), [#ruby](https://daily.dev/tags/ruby), [#rails](https://daily.dev/tags/rails)

[View this post on daily.dev](https://daily.dev/posts/the-persistence-apis-that-skip-the-record-lifecycle-l3eb62qjm)
