ruby-on-railsrubyversioningpaper-trail-gem

Paper trail version history unexpectedly contains record not matching conditional


As per this Readme section, I specify that I only want my record to be tracked when the following conditional is met:

has_paper_trail only: [:body], if: Proc.new { |p| !p.draft }

This code is in my Post model. In other words, I only want versioning for posts that are not drafts.

To my surprise, changing a post from draft to non-draft stores the draft version:

> Post.last.update body: 'bar', draft: false
> Post.last.versions.count
 => 1
> Post.last.versions.last.reify
 => #<Post id: 274, body: "foo", draft: true ...>
                                        ^

I don't want to track draft posts. My impression is that the draft version should not be stored since it does not meet my conditional. I would have expected versioning to start after the conditional is met, not before.

Or am I misunderstanding something or using the gem wrong?


Solution

  • The behavior makes kind of sense to me because when the status changed from draft to something else then the status is at the time of saving the record not draft anymore and therefore the previous version will be stored.

    If you do not want to store the last draft version then you need to change your condition to this

    has_paper_trail only: [:body], if: Proc.new { |p| !p.draft && !p.draft_was }
    

    or this

    has_paper_trail only: [:body], if: Proc.new { |p| !p.draft && !p.draft_previously_was }
    

    draft_was and draft_previously_was are methods generated by ActiveModel::Dirty.

    Both – dirty attributes and paper trail – are called and running during the phase after a record was saved into the database and the database change was committed. Depending on which runs first draft_was still might be set when paper trail checks the condition or draft_was might already be reset but then draft_previously_was should be set instead.