How to get original attribute for a model with paper trail

Viewed 1647

I have a model that is tracked with paper trail. I need to compare the current value to the values model was created. So far i can get the current value easily. How to i get the original?

To get current value: widget.name

to get the original: widget.versions.first.???.name

I know that widget.versions.first.changeset will return a hash like this:

{
  name: [nil, 'original name']
}

But i don't want to parse it out, there has to be a better way

3 Answers

I wen't about doing this:

original = widget.versions.where(event: 'create')[0].changeset['name'][1]

Ugly but works well. Can monkey patch it into paper_trail to clean it up

Use reify on the second version or return the widget if not present.

There's a closed issue about reify returning nil on the Github repo. It got ignored over there but I think this is a very valid issue and a common use-case.

Doing widget.versions.first.reify returns nil so the best way I could find is this:

widget.versions.second.reify

But that doesn't work when the object doesn't have any changes. So you need a nil check in there:

widget.versions.second&.reify || widget

This looks for the second version and if it's present will call reify, which returns the original object. If it's not present it will simply return the widget itself.

If you want to be clean about it, you can add this as a method to the class:

# Returns the original version of this object or just this object if there has been no changes.
def original_version
  self.versions.second&.reify || self
end

I have an open Issue/Feature Request with PaperTrail to add original_version to the core library itself:

https://github.com/paper-trail-gem/paper_trail/issues/1204

Give it an upvote if you want it in there.

something that you can also do (a bit hacky and could not work on all use cases) is:

class MyModel
  has_paper_trail on: [:touch]
  after_save { touch }
end

That way:

  • you have the create version in your versions
  • you have the live version in your versions
  • BUT you cannot leverage the version#event anymore (it will always be "touch")
Related