Touch
The Touch functionality in CQL Active Record allows you to update timestamp fields (like updated_at, created_at, or custom timestamp fields) without triggering any callbacks like validations, before/after save hooks, or other lifecycle callbacks.
This is particularly useful when you want to mark records as "recently accessed" or update timestamps for logging purposes without running the full save cycle.
Overview
Touch provides a lightweight way to update timestamp columns directly in the database, bypassing the entire Active Record callback chain including:
Validation callbacks (
before_validation,after_validation)Save callbacks (
before_save,after_save)Create/Update callbacks (
before_create,after_create,before_update,after_update)
Basic Usage
Instance Methods
#touch(*fields, time: Time = Time.utc)
#touch(*fields, time: Time = Time.utc)Updates specified timestamp fields to the current time (or a custom time) without running callbacks.
# Touch the default updated_at field
user.touch
# => Updates user.updated_at to current time
# Touch specific timestamp fields
user.touch(:last_seen_at)
# => Updates user.last_seen_at to current time
# Touch multiple fields
user.touch(:updated_at, :last_accessed_at)
# => Updates both fields to current time
# Touch with custom time
specific_time = Time.utc - 1.hour
user.touch(:updated_at, time: specific_time)
# => Updates user.updated_at to the specified time#touch!(time: Time = Time.utc)
#touch!(time: Time = Time.utc)Convenience method that specifically touches the updated_at field.
Class Methods
.touch_all(ids, *fields, time: Time = Time.utc)
.touch_all(ids, *fields, time: Time = Time.utc)Updates timestamp fields for multiple records by their IDs without loading them into memory or running callbacks.
Examples
Basic Record Touching
Tracking User Activity
Cache Invalidation
Behavior Details
What Touch Does
Updates Database Directly: Executes an UPDATE query directly against the database
Updates Local Instance: Synchronizes the local object's timestamp attributes with the database
Returns Success Status: Returns
trueif the update was successful,falseotherwiseNo Callbacks: Completely bypasses all Active Record callbacks and validations
What Touch Doesn't Do
No Validation: Does not run any model validations
No Callbacks: Does not trigger any lifecycle callbacks
No Dirty Tracking: Does not mark attributes as changed/dirty
No Version Bumping: Does not increment optimistic locking version numbers
Error Conditions
Touch will raise errors in these situations:
Use Cases
1. Activity Tracking
Update last_seen_at timestamps when users access the application:
2. Cache Invalidation
Mark records as updated to invalidate cached data:
3. Background Job Processing
Update processing timestamps in background jobs:
4. API Rate Limiting
Track API usage without expensive model updates:
Performance Benefits
Touch is significantly more performant than regular saves because it:
Skips validation logic
Bypasses callback chains
Executes minimal SQL UPDATE statements
Doesn't instantiate full objects for batch operations
Avoids complex change tracking
This makes it ideal for high-frequency timestamp updates like activity tracking, cache invalidation, and background processing scenarios.
Comparison with Regular Save
user.save!
✅ All callbacks run
✅ Full validation
Multiple (if callbacks query DB)
Slower
user.touch
❌ No callbacks
❌ No validation
Single UPDATE
Faster
User.touch_all(ids)
❌ No callbacks
❌ No validation
Single UPDATE with IN clause
Fastest
Best Practices
Use for Timestamp Updates: Touch is designed specifically for timestamp fields
Prefer Batch Operations: Use
touch_allfor updating multiple records efficientlyAvoid for Business Logic: Don't use touch when you need validations or callbacks
Consider Cache Impact: Remember that touching may affect timestamp-based caching
Monitor Performance: Touch is fast, but avoid excessive database updates in tight loops
Integration with Existing Code
Touch integrates seamlessly with existing Active Record models. Simply add timestamp properties to your models and start using the touch methods:
The touch functionality respects your existing schema and will work with any Time-typed columns in your database tables.
Last updated
Was this helpful?