Skip to content

Commit

Permalink
Merge pull request #1056 from airblade/request_variables2
Browse files Browse the repository at this point in the history
A new API for request variables, eg. whodunnit
  • Loading branch information
jaredbeck authored Feb 27, 2018
2 parents 0f3d8c8 + 04a58ee commit 6b3e503
Show file tree
Hide file tree
Showing 23 changed files with 766 additions and 320 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
*.gem
*.sqlite3-journal
.bundle
.byebug_history
.idea
.rbenv-gemsets
.rbenv-version
.rspec_results
.ruby-gemset
.ruby-version
.rvmrc
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,17 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
- Removed `warn_about_not_setting_whodunnit` controller method. Please remove
callbacks like `skip_after_action :warn_about_not_setting_whodunnit`.

### Deprecated

- [#1033](https://github.com/airblade/paper_trail/pull/1033) - Request variables
are now set using eg. `PaperTrail.request.whodunnit=` and the old way,
`PaperTrail.whodunnit=` is deprecated.

### Added

- [#1033](https://github.com/airblade/paper_trail/pull/1033) -
Set request variables temporarily using a block, eg.
`PaperTrail.request(whodunnit: 'Jared') do .. end`
- [#1037](https://github.com/airblade/paper_trail/pull/1037) Add `paper_trail.update_columns`
- [#961](https://github.com/airblade/paper_trail/issues/961) - Instead of
crashing when misconfigured Custom Version Classes are used, an error will be
Expand Down
110 changes: 52 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,10 @@ Once you have a version, you can find out what happened:

```ruby
v = widget.versions.last
v.event # 'update', 'create', or 'destroy'
v.created_at # When the `event` occurred
v.whodunnit # If the update was via a controller and the
# controller has a current_user method, returns the
# id of the current user as a string.
widget = v.reify # The widget as it was before the update
# (nil for a create event)
v.event # 'update', 'create', 'destroy'. See also: Custom Event Names
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
Expand Down Expand Up @@ -204,17 +201,12 @@ widget.paper_trail.next_version
# version)
widget.paper_trail.touch_with_version

# Turn PaperTrail off for all widgets.
Widget.paper_trail.disable

# Turn PaperTrail on for all widgets.
Widget.paper_trail.enable
# Enable/disable PaperTrail, for Widget, for the current request (not all threads)
PaperTrail.request.disable_model(Widget)
PaperTrail.request.enable_model(Widget)

# Is PaperTrail enabled for Widget, the class?
Widget.paper_trail.enabled?

# Is PaperTrail enabled for widget, the instance?
widget.paper_trail.enabled_for_model?
PaperTrail.request.enabled_for_model?(Widget)
```

And a `PaperTrail::Version` instance (which is just an ordinary ActiveRecord
Expand Down Expand Up @@ -298,11 +290,12 @@ end
other callbacks in your model, their order relative to those installed by
PaperTrail may matter, so be aware of any potential interactions.

#### Custom Event Name

You may also have the `PaperTrail::Version` model save a custom string in its
`event` field instead of the typical `create`, `update`, `destroy`. PaperTrail
supplies a custom accessor method called `paper_trail_event`, which it will
attempt to use to fill the `event` field before falling back on one of the
default events.
adds an `attr_accessor` to your model named `paper_trail_event`, and will insert
it, if present, in the `event` column.

```ruby
a = Article.create
Expand Down Expand Up @@ -480,18 +473,21 @@ Add a `paper_trail_enabled_for_controller` method to your controller.
```ruby
class ApplicationController < ActionController::Base
def paper_trail_enabled_for_controller
request.user_agent != 'Disable User-Agent'
super && request.user_agent != 'Disable User-Agent'
end
end
```

#### Per Class

```ruby
Widget.paper_trail.disable
Widget.paper_trail.enable
PaperTrail.request.enable_model(Widget)
PaperTrail.request.disable_model(Widget)
```

This setting, as with all `PaperTrail.request` settings, affects only the
current request, not all threads.

#### Per Method

You can call a method without creating a new version using `without_versioning`.
Expand All @@ -509,7 +505,7 @@ Or a block:
end
```

PaperTrail is disabled for the whole model
During `without_versioning`, PaperTrail is disabled for the whole model
(e.g. `Widget`), not just for the instance (e.g. `@widget`).

### 2.e. Limiting the Number of Versions Created
Expand Down Expand Up @@ -703,34 +699,44 @@ PaperTrail::Version.delete_all ['created_at < ?', 1.week.ago]

### 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.
Set `PaperTrail.request.whodunnit=`, and that value will be stored in the
version's `whodunnit` column.

```ruby
PaperTrail.whodunnit = 'Andy Stewart'
PaperTrail.request.whodunnit = 'Andy Stewart'
widget.update_attributes name: 'Wibble'
widget.versions.last.whodunnit # Andy Stewart
widget.versions.last.whodunnit # Andy Stewart
```

`whodunnit` also accepts a block, a convenient way to temporarily set the value.
#### Setting `whodunnit` to a `Proc`

`whodunnit=` also accepts a `Proc`, in the rare case that lazy evaluation is
required.

```ruby
PaperTrail.whodunnit('Dorian Marié') do
widget.update_attributes name: 'Wibble'
PaperTrail.request.whodunnit = proc do
caller.first{ |c| c.starts_with? Rails.root.to_s }
end
```

`whodunnit` also accepts a `Proc`.
Because lazy evaluation can be hard to troubleshoot, this is not
recommended for common use.

#### Setting `whodunnit` Temporarily

To set whodunnit temporarily, for the duration of a block, use
`PaperTrail.request`:

```ruby
PaperTrail.whodunnit = proc do
caller.first{ |c| c.starts_with? Rails.root.to_s }
PaperTrail.request(whodunnit: 'Dorian Marié') do
widget.update_attributes name: 'Wibble'
end
```

#### Setting `whodunnit` with a controller callback

If your controller has a `current_user` method, PaperTrail provides a
`before_action` that will assign `current_user.id` to `PaperTrail.whodunnit`.
You can add this `before_action` to your `ApplicationController`.
callback that will assign `current_user.id` to `whodunnit`.

```ruby
class ApplicationController
Expand All @@ -752,36 +758,24 @@ end

See also: [Setting whodunnit in the rails console][33]

Sometimes you want to define who is responsible for a change in a small scope
without overwriting value of `PaperTrail.whodunnit`. It is possible to define
the `whodunnit` value for an operation inside a block like this:

```ruby
PaperTrail.whodunnit = 'Andy Stewart'
widget.paper_trail.whodunnit('Lucas Souza') do
widget.update_attributes name: 'Wibble'
end
widget.versions.last.whodunnit # Lucas Souza
widget.update_attributes name: 'Clair'
widget.versions.last.whodunnit # Andy Stewart
```
#### Terminator and Originator

A version's `whodunnit` records who changed the object causing the `version` to
be stored. Because a version stores the object as it looked before the change
(see the table above), `whodunnit` returns who stopped the object looking like
this -- not who made it look like this. Hence `whodunnit` is aliased as
`terminator`.
A version's `whodunnit` column tells us who changed the object, causing the
`version` to be stored. Because a version stores the object as it looked before
the change (see the table above), `whodunnit` tells us who *stopped* the object
looking like this -- not who made it look like this. Hence `whodunnit` is
aliased as `terminator`.

To find out who made a version's object look that way, use
`version.paper_trail_originator`. And to find out who made a "live" object look
like it does, call `paper_trail_originator` on the object.

```ruby
widget = Widget.find 153 # assume widget has 0 versions
PaperTrail.whodunnit = 'Alice'
PaperTrail.request.whodunnit = 'Alice'
widget.update_attributes name: 'Yankee'
widget.paper_trail.originator # 'Alice'
PaperTrail.whodunnit = 'Bob'
PaperTrail.request.whodunnit = 'Bob'
widget.update_attributes name: 'Zulu'
widget.paper_trail.originator # 'Bob'
first_version, last_version = widget.versions.first, widget.versions.last
Expand Down Expand Up @@ -1117,7 +1111,7 @@ module PaperTrail
end
```

This unsupported workaround has been tested with protected_attributes 1.0.9 /
This *unsupported workaround* has been tested with protected_attributes 1.0.9 /
rails 4.2.8 / paper_trail 7.0.3.

## 6. Extensibility
Expand Down Expand Up @@ -1392,7 +1386,7 @@ describe 'RSpec test group' do
end
```

The helper will also reset the `PaperTrail.whodunnit` value to `nil` before each
The helper will also reset `whodunnit` to `nil` before each
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.
Expand Down Expand Up @@ -1489,7 +1483,7 @@ Given /I want versioning on my model/ do
end
```

The helper will also reset the `PaperTrail.whodunnit` value to `nil` before each
The helper will also reset the `whodunnit` value to `nil` before each
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.
Expand Down
Loading

0 comments on commit 6b3e503

Please sign in to comment.