← Back to list

Understanding Rails’ touch Method: A Surprising Behavior with Attributes

Ahmed A. Ibrahim · 2024-12-10 12:03 · 25 claps · 1.6 min read paywalled
#ruby #rails #ruby-on-rails #activerecord
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Understanding Rails’ touch Method: A Surprising Behavior with Attributes

When working with Ruby on Rails, the touch method is a handy way to update the updated_at timestamp of a record. However, when you pass an attribute to touch, the behavior can sometimes be surprising, as I recently discovered.

The Unexpected Behavior

Consider this scenario:

Product.last.touch(:price)

I expected this to only update the updated_at timestamp and "touch" the price attribute for triggering callbacks or observers. Instead, the price attribute was updated to a timestamp value (2024)!

Why Did This Happen?

The touch method, when passed an attribute, does two things:

  1. Updates the updated_at timestamp of the record.
  2. Updates the specified attribute with the current timestamp (Time.current) if the attribute’s column type supports timestamps.

In my case, the price column was defined in a way that allowed timestamp values (e.g., as a string, datetime, or similar type). Rails interpreted my touch(:price) call as an instruction to set price to the current time.

This behavior is intentional, as Rails assumes the attribute you “touch” is meant to store a timestamp.

Understanding the SQL Queries

Here’s what happens under the hood for these calls:

  1. Without an attribute:
Product.last.touch

This generates the following SQL query, updating only the updated_at column:

UPDATE products
SET updated_at = '2024-12-10 12:00:00'
WHERE id = 1;
  1. With an attribute:
Product.last.touch(:price)

This generates a query that updates both updated_at and the price column:

UPDATE products
SET updated_at = '2024-12-10 12:00:00', price = '2024-12-10 12:00:00'
WHERE id = 1;

How to Avoid This Issue

If you don’t want to unintentionally overwrite the price column (or any other non-timestamp column), here are some safe practices:

1. Call touch Without an Attribute

To only update the updated_at timestamp, use:

Product.last.touch

This ensures no other attribute is affected.

2. Check the Column Type

Before using touch with an attribute, verify the column’s type:

Product.columns_hash["price"].type

If the column isn’t meant to store timestamps (e.g., it’s an integer or decimal), avoid passing it to touch.

3. Manually Restore the Attribute

If you accidentally overwrite the column, you can restore its value:

product = Product.last
original_price = product.price
product.touch(:price)
product.update(price: original_price)

4. Consider Database Migrations

If the price column is incorrectly defined as a string or datetime, consider updating its type:

class ChangePriceToDecimalInProducts < ActiveRecord::Migration[7.0]
  def change
    change_column :products, :price, :decimal
  end
end

Conclusion

While Rails’ touch method is powerful, its behavior with attributes can be surprising if you’re not aware of the nuances. By understanding how it works and taking precautions, you can avoid unexpected issues in your applications.


메타데이터
post_id
13bc458dfceb
slug
understanding-rails-touch-method-a-surprising-behavior-with-attributes-13bc458dfceb
url
https://medium.com/@ahmed_aly/understanding-rails-touch-method-a-surprising-behavior-with-attributes-13bc458dfceb
canonical_url
https://medium.com/@ahmed_aly/understanding-rails-touch-method-a-surprising-behavior-with-attributes-13bc458dfceb
author_url
https://medium.com/@ahmed_aly
status
ok
fetched_at
2026-07-21 17:34:17