Reputation: 46379
I'm looking for a way to add a *_updated_at
columns for several columns in a record.
It would work similarly to normal Rails timestamps, ie based on convention. If there's a DB column called author_updated_at
, the class would automagically update it whenever author
attribute changes.
Not too hard to write, but thought I'd ask here in case anyone has done it before or there's a gem around. I'd also be interested to know if there are any performance issues with this approach, though I think it should be negligible if using before_save
. There's no extra reads or writes needed.
Upvotes: 1
Views: 692
Reputation: 2923
I solved with a different version of @max solution.
previous_changes
wasn't working for me. I'm using Rails 4.2.
module AttributeTimestampable
extend ActiveSupport::Concern
included do
after_save do
self.changed.each do |attr|
timestamp = "#{attr}_updated_at"
update_column(timestamp, updated_at) if self.respond_to? timestamp
end
end
end
end
Upvotes: 1
Reputation: 101811
You might want to try paper_trail - it tracks changes to a model but in a slightly different fashion - instead of adding extra columns for each attribute to track it uses a table to store versions of the model. This gives you a full blown versioning system without doing much work.
You can easily revert to previous versions and track who created a revision etc.
But if all you need is a light-weight solution to store a timestamp for the changes to a limited set of attributes you can use model callbacks to set the *_updated_at
columns.
module AttributeTimestamps
extend ActiveSupport::Concern
included do
after_validation(on: :update) do
# Use ActiveModel::Dirty to get the changed attributes
self.previous_changes.each_with_index do |attr|
setter = "#{attr}_updated_at="
self.call(setter, self.updated_at) if self.respond_to? setter
end
end
end
end
class MyModel < ActiveRecord::Base
include AttributeTimestamps
end
Upvotes: 4