Testing the versions table with PaperTrail and RSpec

26 Oct 2021

The PaperTrail gem provides version tracking for your ActiveRecord models but the creation of version entries is skipped in the test environment. This post investigates how to turn on and test versioning for specific tests for situations where your application might be using the versions table.


The introduction from the PaperTrail repo summarises its functionality nicely:

"Track changes to your models, for auditing or versioning. See how a model looked at any stage in its lifecycle, revert it to any version, or restore it after it has been destroyed."

This means that depending on your configuration an entry in the versions table will be created whenever a model that has versioning enabled is either created/updated/destroyed. This entry will have a reference to the object it belongs to as well as its type, state at the time of change and any attributes that were changed. This functionality allows us to track any changes to a specific record over time. Let's take a look at a contrived example:

aircraft = Aircraft.first

aircraft.versions.count #=> 1
# <PaperTrail::Version:0x00007f942781e968
#  id: 14193,
#  item_type: "Aircraft",
#  item_id: "ad4a21e9-53f0-43d3-b59d-464ed9dc23f2",
#  event: "create",
#  whodunnit: "26c108b6-4f9b-4250-82dd-7c2963b23a6e",
#  object: nil,
#  object_changes: "a string representing a hash of object changes...",
#  justification: nil,
#  signature_id: nil,
#  created_at: Wed, 11 Aug 2021 16:07:58 UTC +00:00>

Version Testing with RSpec

The reason I created this post is because by default the creation of version records in the versions table is skipped by default in the test environment. To increase the performance of your test suite PaperTrail allows you to turn on versioning for specific tests or blocks of tests. The following test will fail because versioning is disabled:

# app/models/aircraft.rb

describe Aircraft do
  it "versions the aircraft" do
    aircraft = Aircraft.create!

    expect(aircraft.versions.count).to eq(1)

However, with some minor adjustments we can make it pass:

# app/models/aircraft.rb

require 'paper_trail/frameworks/rspec'

describe Aircraft do
  it "versions the aircraft", versioning: true do
    aircraft = Aircraft.create!

    expect(aircraft.versions.count).to eq(1)

Here we are importing the PaperTrail helper at the top of the file that provides us with functionalities to enable and test the versions table. We've then passed the versioning: true option to the it block that specifies our assertion. Now versioning of our Aircraft records is enabled for this test only so we can test those versions as required without worrying about bloating our test database and increasing the time of our test suite.

There are other excellent helper methods and functionalities that are made available once you import the helper. I recommend checking out the link below so you can best find the approach that suits your use case!