Docs: Add ordinal numbers to headers in readme

Numbering the headers improves document navigation and
reference-ability. Unfortunately, it does break the anchor
part of links in the wild.

[ci skip]
This commit is contained in:
Jared Beck 2016-05-10 23:43:33 -04:00
parent 29c0dc9335
commit 717193e570
1 changed files with 93 additions and 102 deletions

195
README.md
View File

@ -19,34 +19,38 @@ has been destroyed.
## Table of Contents
- [Compatibility](#compatibility)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [API Summary](#api-summary)
- Limiting What is Versioned, and When
- [Choosing Lifecycle Events To Monitor](#choosing-lifecycle-events-to-monitor)
- [Choosing When To Save New Versions](#choosing-when-to-save-new-versions)
- [Choosing Attributes To Monitor](#choosing-attributes-to-monitor)
- [Turning PaperTrail Off](#turning-papertrail-off)
- [Limiting the Number of Versions Created](#limiting-the-number-of-versions-created)
- Working With Versions
- [Reverting And Undeleting A Model](#reverting-and-undeleting-a-model)
- [Navigating Versions](#navigating-versions)
- [Diffing Versions](#diffing-versions)
- [Deleting Old Versions](#deleting-old-versions)
- Saving More Information About Versions
- [Finding Out Who Was Responsible For A Change](#finding-out-who-was-responsible-for-a-change)
- [Associations](#associations)
- [Storing metadata](#storing-metadata)
- ActiveRecord
- [Single Table Inheritance](#single-table-inheritance-sti)
- Extensibility
- [Custom Version Classes](#custom-version-classes)
- [Custom Serializer](#custom-serializer)
- [Testing](#testing)
- [Sinatra](#sinatra)
- [1. Introduction](#1-introduction)
- [1.a. Compatibility](#1a-compatibility)
- [1.b. Installation](#1b-installation)
- [1.c. Basic Usage](#1c-basic-usage)
- [1.d. API Summary](#1d-api-summary)
- [2. Limiting What is Versioned, and When](#2-limiting-what-is-versioned-and-when)
- [2.a. Choosing Lifecycle Events To Monitor](#2a-choosing-lifecycle-events-to-monitor)
- [2.b. Choosing When To Save New Versions](#2b-choosing-when-to-save-new-versions)
- [2.c. Choosing Attributes To Monitor](#2c-choosing-attributes-to-monitor)
- [2.d. Turning PaperTrail Off](#2d-turning-papertrail-off)
- [2.e. Limiting the Number of Versions Created](#2e-limiting-the-number-of-versions-created)
- [3. Working With Versions](#3-working-with-versions)
- [3.a. Reverting And Undeleting A Model](#3a-reverting-and-undeleting-a-model)
- [3.b. Navigating Versions](#3b-navigating-versions)
- [3.c. Diffing Versions](#3c-diffing-versions)
- [3.d. Deleting Old Versions](#3d-deleting-old-versions)
- [4. Saving More Information About Versions](#4-saving-more-information-about-versions)
- [4.a. Finding Out Who Was Responsible For A Change](#4a-finding-out-who-was-responsible-for-a-change)
- [4.b. Associations](#4b-associations)
- [4.c. Storing metadata](#4c-storing-metadata)
- [5. ActiveRecord](#5-activerecord)
- [5.a. Single Table Inheritance](#5a-single-table-inheritance-sti)
- [5.b. Configuring the `versions` Association](#5b-configuring-the-versions-association)
- [6. Extensibility](#6-extensibility)
- [6.a. Custom Version Classes](#6a-custom-version-classes)
- [6.b. Custom Serializer](#6b-custom-serializer)
- [7. Testing](#7-testing)
- [8. Sinatra](#8-sinatra)
## Compatibility
## 1. Introduction
### 1.a. Compatibility
| paper_trail | branch | tags | ruby | activerecord |
| -------------- | ---------- | ------ | -------- | ------------ |
@ -56,7 +60,7 @@ has been destroyed.
| 2 | 2.7-stable | v2.x | >= 1.8.7 | >= 3.0, < 4 |
| 1 | rails2 | v1.x | >= 1.8.7 | >= 2.3, < 3 |
## Installation
### 1.b. Installation
1. Add PaperTrail to your `Gemfile`.
@ -90,7 +94,7 @@ by adding a controller callback.
end
```
## Basic Usage
### 1.c. Basic Usage
Your models now have a `versions` method which returns the "paper trail" of
changes to your model.
@ -146,7 +150,7 @@ Here's a helpful table showing what PaperTrail stores:
PaperTrail stores the values in the Model Before column. Most other
auditing/versioning plugins store the After column.
## API Summary
### 1.d. API Summary
When you declare `has_paper_trail` in your model, you get these methods:
@ -246,7 +250,9 @@ user_for_paper_trail
info_for_paper_trail
```
## Choosing Lifecycle Events To Monitor
## 2. Limiting What is Versioned, and When
### 2.a. Choosing Lifecycle Events To Monitor
You can choose which events to track with the `on` option. For example, to
ignore `create` events:
@ -281,7 +287,7 @@ a.versions.size # 3
a.versions.last.event # 'update'
```
### Controlling the Order of AR Callbacks
#### Controlling the Order of AR Callbacks
The `has_paper_trail` method installs AR callbacks. If you need to control
their order, use the `paper_trail_on_*` methods.
@ -305,7 +311,7 @@ The `paper_trail_on_destroy` method can be further configured to happen
`:after`. In PaperTrail 5, the default will be `:before`, to support
ActiveRecord 5. (see https://github.com/airblade/paper_trail/pull/683)
## Choosing When To Save New Versions
### 2.b. Choosing When To Save New Versions
You can choose the conditions when to add new versions with the `if` and
`unless` options. For example, to save versions only for US non-draft
@ -318,13 +324,13 @@ class Translation < ActiveRecord::Base
end
```
### Choosing Based on Changed Attributes
#### Choosing Based on Changed Attributes
Starting with PaperTrail 4.0, versions are saved during an after-callback. If
you decide whether to save a new version based on changed attributes, please
use attribute_name_was instead of attribute_name.
## Choosing Attributes To Monitor
### 2.c. Choosing Attributes To Monitor
You can ignore changes to certain attributes like this:
@ -411,11 +417,11 @@ class Article < ActiveRecord::Base
end
```
## Turning PaperTrail Off
### 2.d. Turning PaperTrail Off
PaperTrail is on by default, but sometimes you don't want to record versions.
### Per Process
#### Per Process
Turn PaperTrail off for all threads in a `ruby` process.
@ -432,7 +438,7 @@ There is also a rails config option that does the same thing.
config.paper_trail.enabled = false
```
### Per Request
#### Per Request
Add a `paper_trail_enabled_for_controller` method to your controller.
@ -444,14 +450,14 @@ class ApplicationController < ActionController::Base
end
```
### Per Class
#### Per Class
```ruby
Widget.paper_trail_off!
Widget.paper_trail_on!
```
### Per Method
#### Per Method
You can call a method without creating a new version using `without_versioning`.
It takes either a method name as a symbol:
@ -468,7 +474,7 @@ Or a block:
end
```
## Limiting the Number of Versions Created
### 2.e. Limiting the Number of Versions Created
Configure `version_limit` to cap the number of versions saved per record. This
does not apply to `create` events.
@ -480,7 +486,9 @@ PaperTrail.config.version_limit = 3
PaperTrail.config.version_limit = nil
```
## Reverting And Undeleting A Model
## 3. Working With Versions
### 3.a. Reverting And Undeleting A Model
PaperTrail makes reverting to a previous version easy:
@ -517,7 +525,7 @@ You could even use PaperTrail to implement an undo system, [Ryan Bates has!][3]
If your model uses [optimistic locking][1] don't forget to [increment your
`lock_version`][2] before saving or you'll get a `StaleObjectError`.
## Navigating Versions
### 3.b. Navigating Versions
You can call `previous_version` and `next_version` on an item to get it as it
was/became. Note that these methods reify the item for you.
@ -573,7 +581,7 @@ And you can perform `WHERE` queries for object versions based on attributes:
PaperTrail::Version.where_object(content: "Hello", title: "Article")
```
## Diffing Versions
### 3.c. Diffing Versions
There are two scenarios: diffing adjacent versions and diffing non-adjacent
versions.
@ -638,7 +646,7 @@ If you wish to selectively record changes for some models but not others you
can opt out of recording changes by passing `:save_changes => false` to your
`has_paper_trail` method declaration.
## Deleting Old Versions
### 3.d. Deleting Old Versions
Over time your `versions` table will grow to an unwieldy size. Because each
version is self-contained (see the Diffing section above for more) you can
@ -652,7 +660,9 @@ sql> delete from versions where created_at < 2010-06-01;
PaperTrail::Version.delete_all ["created_at < ?", 1.week.ago]
```
## Finding Out Who Was Responsible For A Change
## 4. Saving More Information About Versions
### 4.a. Finding Out Who Was Responsible For A Change
Set `PaperTrail.whodunnit=`, and that value will be stored in the version's
`whodunnit` column.
@ -730,12 +740,12 @@ last_version.paper_trail_originator # 'Alice'
last_version.terminator # 'Bob'
```
### Storing an ActiveRecord globalid in whodunnit
#### Storing an ActiveRecord globalid in whodunnit
If you would like `whodunnit` to return an `ActiveRecord` object instead of a
string, please try the [paper_trail-globalid][37] gem.
## Associations
### 4.b. Associations
**Experimental feature**, see caveats below.
@ -841,7 +851,7 @@ widget.reload.wotsit # nil
rails until ActiveRecord 4.2 (https://github.com/rails/rails/pull/14359).
1. PaperTrail can't restore an association properly if the association record
can be updated to replace its parent model (by replacing the foreign key)
1. Currently PaperTrail only support single `version_associations` table. The
1. Currently PaperTrail only supports a single `version_associations` table. The
implication is that you can only use a single table to store the versions for
all related models. Sorry for those who use multiple version tables.
1. PaperTrail only reifies the first level of associations, i.e., it does not
@ -914,7 +924,7 @@ end
See [issue 113][16] for a discussion about this.
## Storing Metadata
### 4.c. Storing Metadata
You can store arbitrary model-level metadata alongside each version like this:
@ -934,7 +944,7 @@ PaperTrail will call your proc with the current article and store the result in
the `author_id` column of the `versions` table.
Don't forget to add any such columns to your `versions` table.
### Advantages of Metadata
#### Advantages of Metadata
Why would you do this? In this example, `author_id` is an attribute of
`Article` and PaperTrail will store it anyway in a serialized form in the
@ -948,7 +958,7 @@ those versions you want:
PaperTrail::Version.where(:author_id => author_id)
```
### Metadata from Controllers
#### Metadata from Controllers
You can also store any information you like from your controller. Override
the `info_for_paper_trail` method in your controller to return a hash whose keys
@ -962,7 +972,7 @@ class ApplicationController
end
```
### Protected Attributes and Metadata
#### Protected Attributes and Metadata
If you are using rails 3 or the [protected_attributes][17] gem you must declare
your metadata columns to be `attr_accessible`.
@ -980,7 +990,9 @@ end
If you're using [strong_parameters][18] instead of [protected_attributes][17]
then there is no need to use `attr_accessible`.
## Single Table Inheritance (STI)
## 5. ActiveRecord
### 5.a. Single Table Inheritance (STI)
PaperTrail supports [Single Table Inheritance][39], and even supports an
un-versioned base model, as of 23ffbdc7e1.
@ -997,30 +1009,25 @@ end
However, there is a known issue when reifying [associations](#associations),
see https://github.com/airblade/paper_trail/issues/594
## Overriding the `versions` method
### 5.b. Configuring the `versions` Association
Overriding the `versions` method is officially not supported, but you can
change the name of that association. Because `versions` returns an
`ActiveRecord::Relation` object, changes to that method will result in changes
both to how records are retrieved _and_ how records are created.
If you absolutely must override this method to maintain your object's API,
you can do so safely by changing the name of the association.
You may configure the name of the `versions` association by passing
a different name to `has_paper_trail`.
```ruby
module News
class Post < ActiveRecord::Base
has_paper_trail class_name: 'Version', versions: :base_versions
def versions
types = ['Post', 'News::Post']
@versions ||= Version.where(item_id: id, item_type: types)
end
end
class Post < ActiveRecord::Base
has_paper_trail class_name: 'Version', versions: :drafts
end
Post.new.versions # => NoMethodError
```
## Custom Version Classes
Overriding (instead of configuring) the `versions` method is not supported.
Overriding associations is not recommended in general.
## 6. Extensibility
### 6.a. Custom Version Classes
You can specify custom version subclasses with the `:class_name` option:
@ -1037,13 +1044,13 @@ end
Unlike ActiveRecord's `class_name`, you'll have to supply the complete module path to the class (e.g. `Foo::BarVersion` if your class is inside the module `Foo`).
### Advantages
#### Advantages
1. For models which have a lot of versions, storing each model's versions in a
separate table can improve the performance of certain database queries.
1. Store different version [metadata](#storing-metadata) for different models.
### Configuration
#### Configuration
If you are using Postgres, you should also define the sequence that your custom
version class will use:
@ -1089,7 +1096,7 @@ class Post < ActiveRecord::Base
end
```
## Custom Serializer
### 6.b. Custom Serializer
By default, PaperTrail stores your changes as a `YAML` dump. You can override
this with the serializer config option:
@ -1104,7 +1111,7 @@ method. These serializers are included in the gem for your convenience:
* [PaperTrail::Serializers::YAML][24] - Default
* [PaperTrail::Serializers::JSON][25]
### PostgreSQL JSON column type support
#### PostgreSQL JSON column type support
If you use PostgreSQL, and would like to store your `object` (and/or
`object_changes`) data in a column of [type `json` or type `jsonb`][26], specify
@ -1122,7 +1129,7 @@ end
If you use the PostgreSQL `json` or `jsonb` column type, you do not need
to specify a `PaperTrail.serializer`.
#### Convert existing YAML data to JSON
##### Convert existing YAML data to JSON
If you've been using PaperTrail for a while with the default YAML serializer
and you want to switch to JSON or JSONB, you're in a bit of a bind because
@ -1174,7 +1181,7 @@ remove_column :versions, :old_object
If you use the optional `object_changes` column, don't forget to convert it
also, using the same technique.
#### Convert a Column from Text to JSON
##### Convert a Column from Text to JSON
If your `object` column already contains JSON data, and you want to change its
data type to `json` or `jsonb`, you can use the following [DDL][36]. Of course,
@ -1203,12 +1210,12 @@ class ConvertVersionsObjectToJson < ActiveRecord::Migration
end
```
## Testing
## 7. Testing
You may want to turn PaperTrail off to speed up your tests. See [Turning
PaperTrail Off](#turning-papertrail-off) above.
### Minitest
### 7.a. Minitest
First, disable PT for the entire `ruby` process.
@ -1248,7 +1255,7 @@ test "something that needs versioning" do
end
```
### RSpec
### 7.b. RSpec
PaperTrail provides a helper, `paper_trail/frameworks/rspec.rb`, that works with
[RSpec][27] to make it easier to control when `PaperTrail` is enabled during
@ -1338,7 +1345,7 @@ matcher
```
### Cucumber
### 7.c. Cucumber
PaperTrail provides a helper for [Cucumber][28] that works similar to the RSpec
helper.If you wish to use the helper, you will need to require in your cucumber
@ -1371,7 +1378,7 @@ test to help prevent data spillover between tests. If you are using PaperTrail
with Rails, the helper will automatically set the `PaperTrail.controller_info`
value to `{}` as well, again, to help prevent data spillover between tests.
### Spork
### 7.d. Spork
If you wish to use the `RSpec` or `Cucumber` helpers with [Spork][29], you will
need to manually require the helper(s) in your `prefork` block on your test
@ -1394,7 +1401,7 @@ Spork.prefork do
end
```
### Zeus or Spring
### 7.e. Zeus or Spring
If you wish to use the `RSpec` or `Cucumber` helpers with [Zeus][30] or
[Spring][31], you will need to manually require the helper(s) in your test
@ -1410,25 +1417,9 @@ require 'rspec/rails'
require 'paper_trail/frameworks/rspec'
```
## Testing PaperTrail
## 8. Sinatra
Paper Trail has facilities to test against Postgres, Mysql and SQLite. To switch
between DB engines you will need to export the DB variable for the engine you
wish to test against.
Though be aware we do not have the ability to create the db's (except sqlite) for
you. You can look at .travis.yml before_script for an example of how to create
the db's needed.
```
export DB=postgres
export DB=mysql
export DB=sqlite # this is default
```
## Sinatra
In order to configure PaperTrail for usage with [Sinatra][12], your `Sinatra`
To configure PaperTrail for usage with [Sinatra][12], your `Sinatra`
app must be using `ActiveRecord` 3 or 4. It is also recommended to use the
[Sinatra ActiveRecord Extension][13] or something similar for managing your
applications `ActiveRecord` connection in a manner similar to the way `Rails`