[![Build Status][4]][5] [![Gem Version][53]][54] [![SemVer][55]][56]
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 is the user guide. See also, the API reference.
Choose version: Unreleased, 17.0, 16.0, 15.2, 14.0, 13.0, 12.3, 11.1, 10.3, 9.2, 8.1, 7.1, 6.0, 5.2, 4.2, 3.0, 2.7, 1.6
item_idsversions Association| paper_trail | ruby | activerecord |
|---|---|---|
| unreleased | >= 3.2.0 | >= 7.1, <= 8.1 |
| 17 | >= 3.2.0 | >= 7.1, <= 8.1 |
| 16 | >= 3.0.0 | >= 6.1, <= 8.0 |
| 15.2 | >= 3.0.0 | >= 6.1, <= 7.2 |
| 15.1 | >= 3.0.0 | >= 6.1, <= 7.1 |
| 15 | >= 3.0.0 | >= 6.1, <= 7.1 |
| 14 | >= 2.7.0 | >= 6.0, < 7.1 |
| 13 | >= 2.6.0 | >= 5.2, < 7.1 |
| 12 | >= 2.6.0 | >= 5.2, < 7.1 |
| 11 | >= 2.4.0 | >= 5.2, < 6.1 |
| 10 | >= 2.3.0 | >= 4.2, < 6.1 |
| 9 | >= 2.3.0 | >= 4.2, < 5.3 |
| 8 | >= 2.2.0 | >= 4.2, < 5.2 |
| 7 | >= 2.1.0 | >= 4.0, < 5.2 |
| 6 | >= 1.9.3 | >= 4.0, < 5.2 |
| 5 | >= 1.9.3 | >= 3.0, < 5.1 |
| 4 | >= 1.8.7 | >= 3.0, < 5.1 |
| 3 | >= 1.8.7 | >= 3.0, < 5 |
| 2 | >= 1.8.7 | >= 3.0, < 4 |
| 1 | >= 1.8.7 | >= 2.3, < 3 |
Experts: to install incompatible versions of activerecord, see
paper_trail/compatibility.rb.
Add PaperTrail to your Gemfile and run [bundle][57].
gem 'paper_trail'
Add a versions table to your database:
bundle exec rails generate paper_trail:install [--with-changes] [--uuid]
bundle exec rails db:migrate
See section 5.c. Generators for details.
Add has_paper_trail to the models you want to track.
ruby
class Widget < ActiveRecord::Base
has_paper_trail
end
If your controllers have a current_user method, you can easily track who
is responsible for changes
by adding a controller callback.
ruby
class ApplicationController
before_action :set_paper_trail_whodunnit
end
Review the default initializer that was created by rails generate paper_trail:install
at config/initializers/paper_trail.rb.
Your models now have a versions method which returns the "paper trail" of
changes to your model.
widget = Widget.find 42
widget.versions
# [<PaperTrail::Version>, <PaperTrail::Version>, ...]
Once you have a version, you can find out what happened:
v = widget.versions.last
v.event # 'update', 'create', 'destroy'. See also: "The versions.event Column"
v.created_at
v.whodunnit # ID of `current_user`. Requires `set_paper_trail_whodunnit` callback.
widget = v.reify # The widget as it was before the update (nil for a create event)
PaperTrail stores the pre-change version of the model, unlike some other auditing/versioning plugins, so you can retrieve the original version. This is useful when you start keeping a paper trail for models that already have records in the database.
widget = Widget.find 153
widget.name # 'Doobly'
# Add has_paper_trail to Widget model.
widget.versions # []
widget.update name: 'Wotsit'
widget.versions.last.reify.name # 'Doobly'
widget.versions.last.event # 'update'
This also means that PaperTrail does not waste space storing a version of the
object as it currently stands. The versions method gives you previous
versions; to get the current one just call a finder on your Widget model as
usual.
Here's a helpful table showing what PaperTrail stores:
| Event | create | update | destroy |
|---|---|---|---|
| Model Before | nil | widget | widget |
| Model After | widget | widget | nil |
PaperTrail stores the values in the Model Before row. Most other auditing/versioning plugins store the After row.
An introductory sample of common features.
When you declare has_paper_trail in your model, you get these methods:
class Widget < ActiveRecord::Base
has_paper_trail
end
# Returns this widget's versions. You can customise the name of the
# association, but overriding this method is not supported.
widget.versions
# Return the version this widget was reified from, or nil if it is live.
# You can customise the name of the method.
widget.version
# Returns true if this widget is the current, live one; or false if it is from
# a previous version.
widget.paper_trail.live?
# Returns who put the widget into its current state.
widget.paper_trail.originator
# Returns the widget (not a version) as it looked at the given timestamp.
widget.paper_trail.version_at(timestamp)
# Returns the widget (not a version) as it was most recently.
widget.paper_trail.previous_version
# Returns the widget (not a version) as it became next.
widget.paper_trail.next_version
And a PaperTrail::Version instance (which is just an ordinary ActiveRecord
instance, with all the usual methods) has methods such as:
# Returns the item restored from this version.
version.reify(options = {})
# Return a new item from this version
version.reify(dup: true)
# Returns who put the item into the state stored in this version.
version.paper_trail_originator
# Returns who changed the item from the state it had in this version.
version.terminator
version.whodunnit
version.version_author
# Returns the next version.
version.next
# Returns the previous version.
version.previous
# Returns the index of this version in all the versions.
version.index
# Returns the event that caused this version (create|update|destroy).
version.event
This is just a sample of common features. Keep reading for more.
Many aspects of PaperTrail are configurable for individual models; typically
this is achieved by passing options to the has_paper_trail method within
a given model.
Some aspects of PaperTrail are configured globally for all models. These
settings are assigned directly on the PaperTrail.config object.
A common place to put these settings is in a Rails initializer file
such as config/initializers/paper_trail.rb or in an environment-specific
configuration file such as config/environments/test.rb.
Global configuration options affect all threads.
Syntax example: (options descr
| 日期 | 榜单 | 排名 | 周期新增 | 总 STAR |
|---|