Blog

Thoughts from my daily grind

Tracking attribute changes in ActiveRecord

Posted by Ziyan Junaideen |Published: 24 August 2019 |Category: Ruby on Rails
Default Upload |

Applications are all about data and how that data changes. This is especially true in business and financial applications where there may be legal requirements to address when certain detail changes.

For example, assume you are having a marketplace and you verify users for the safety of everyone. A user decides to change their name. We may need to track the change and send it for review so that a human can follow up and approve.

To assist in these situations, ActiveRecord implements a couple of helpful features. They are:

  • model.[attr_name]_was
  • model.[attr_name]_changed?
  • model.[attr_name]_previously_was
  • model.[attr_name]_previously_changed?
  • model.changes
  • model.previous_changes

Example

User.last

#<User:0x00007f97399d2218
#   id: 8,
#   name: "John Doe",
#   email: nil,
#   created_at: Mon, 11 Apr 2022 18:44:53.719170000 UTC +00:00,
#   updated_at: Wed, 13 Apr 2022 06:10:28.468541000 UTC +00:00,
#   admin: false>

u.name = "Jane Doe"
# => "Jane Doe"

u.name_was
# => "John Doe"

u.name_changed?
# => true

u.name_previously_was
# => nil

u.name_previously_changed?
# => false

u.changes
# => {"name"=>["John Doe", "Jane Doe"]}

u.previous_changes
# => {}

u.save

u.name
# => "Jane Doe"

u.name_was
# => "Jane Doe"

u.name_changed?
# => false

u.name_previously_was
# => "John Doe"

u.name_previously_changed?
# => true

u.changes
# => {}

u.previous_changes
# => {
#       "name"=>["John Doe", "Jane Doe"],
#       "updated_at"=>[
#         Wed, 13 Apr 2022 06:10:28.468541000 UTC +00:00,
#         Wed, 13 Apr 2022 06:12:19.517157000 UTC +00:00
#       ]
#    }

Persistence

It is important to note that these data are not stored in the database and are only available to us during the lifecycle of the object or request. If you require to keep them, you need to implement the feature using ActiveRecord hooks or something similar to Trailblazer Operations.

u.reload

u.name_was
# => "Jane Doe"

u.name
# => "Jane Doe"

u.previous_changes
# => {}

u.changes
# => {}

The [attribute]_previously_was feature comes from a PR from DHH.

Conclusion

The tracking for attribute value changes comes in handy in many web and API projects. It can help display a flash message or something more complex as an identity or address verification. Regardless of your needs, Rails got you covered.

About the Author

Ziyan Junaideen -

Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.

Comments