paper_trail 7.0.0 → 7.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +0 -3
- data/CHANGELOG.md +15 -0
- data/README.md +29 -28
- data/lib/generators/paper_trail/install_generator.rb +59 -1
- data/lib/generators/paper_trail/templates/{add_object_changes_to_versions.rb → add_object_changes_to_versions.rb.erb} +0 -0
- data/lib/generators/paper_trail/templates/{add_transaction_id_column_to_versions.rb → add_transaction_id_column_to_versions.rb.erb} +0 -0
- data/lib/generators/paper_trail/templates/{create_version_associations.rb → create_version_associations.rb.erb} +0 -0
- data/lib/generators/paper_trail/templates/create_versions.rb.erb +36 -0
- data/lib/paper_trail/version_number.rb +1 -1
- data/paper_trail.gemspec +1 -1
- data/spec/generators/install_generator_spec.rb +18 -2
- data/spec/models/boolit_spec.rb +23 -31
- data/spec/models/callback_modifier_spec.rb +74 -78
- data/spec/models/gadget_spec.rb +26 -27
- data/spec/models/joined_version_spec.rb +22 -28
- data/spec/models/skipper_spec.rb +29 -33
- data/spec/models/version_spec.rb +184 -183
- metadata +9 -11
- data/lib/generators/paper_trail/templates/create_versions.rb +0 -80
- data/spec/generators/paper_trail/templates/create_versions_spec.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e92a25394990bd883a845f051763e117abd5d35
|
4
|
+
data.tar.gz: bde729a85a1052106a116e930f3afafdde5ca319
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f2d6eba98c56942424310f2a3cc0c855c264eecc17fa0377dbb4bdad0ed0e15d66190e1043671af4c2f35c9605f0707565bdada142c1a5f8ce6b3eac203c8e3
|
7
|
+
data.tar.gz: 99b7dd59468398c88e7c15f4e8b4fa6a2ba274a1aa8794a2caa8351d54cf6abdc51908449d26e71382b0505f08bcd0cdfbaa8fa2a030f9a76a391e84daafc8db
|
data/.rubocop_todo.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -17,6 +17,21 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
|
|
17
17
|
|
18
18
|
- None
|
19
19
|
|
20
|
+
## 7.0.1 (2017-04-10)
|
21
|
+
|
22
|
+
### Breaking Changes
|
23
|
+
|
24
|
+
- None
|
25
|
+
|
26
|
+
### Added
|
27
|
+
|
28
|
+
- Generate cleaner migrations for databases other than MySQL
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
|
32
|
+
- [#949](https://github.com/airblade/paper_trail/issues/949) - Inherit from the
|
33
|
+
new versioned migration class, e.g. `ActiveRecord::Migration[5.1]`
|
34
|
+
|
20
35
|
## 7.0.0 (2017-04-01)
|
21
36
|
|
22
37
|
### Breaking Changes
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ has been destroyed.
|
|
11
11
|
| Version | Documentation |
|
12
12
|
| -------------- | ------------- |
|
13
13
|
| Unreleased | https://github.com/airblade/paper_trail/blob/master/README.md |
|
14
|
-
| 7.0.
|
14
|
+
| 7.0.1 | https://github.com/airblade/paper_trail/blob/v7.0.0/README.md |
|
15
15
|
| 6.0.2 | https://github.com/airblade/paper_trail/blob/v6.0.2/README.md |
|
16
16
|
| 5.2.3 | https://github.com/airblade/paper_trail/blob/v5.2.3/README.md |
|
17
17
|
| 4.2.0 | https://github.com/airblade/paper_trail/blob/v4.2.0/README.md |
|
@@ -677,7 +677,7 @@ For diffing two ActiveRecord objects:
|
|
677
677
|
* [activerecord-diff][23]: rather like ActiveRecord::Dirty but also allows you
|
678
678
|
to specify which columns to compare.
|
679
679
|
|
680
|
-
If you
|
680
|
+
If you want to selectively record changes for some models but not others you
|
681
681
|
can opt out of recording changes by passing `:save_changes => false` to your
|
682
682
|
`has_paper_trail` method declaration.
|
683
683
|
|
@@ -1151,11 +1151,12 @@ class Post < ActiveRecord::Base
|
|
1151
1151
|
|
1152
1152
|
# Existing versions method. We don't want to clash.
|
1153
1153
|
def versions
|
1154
|
-
...
|
1154
|
+
# ...
|
1155
1155
|
end
|
1156
|
+
|
1156
1157
|
# Existing version method. We don't want to clash.
|
1157
1158
|
def version
|
1158
|
-
...
|
1159
|
+
# ...
|
1159
1160
|
end
|
1160
1161
|
end
|
1161
1162
|
```
|
@@ -1183,10 +1184,10 @@ If you use PostgreSQL, and would like to store your `object` (and/or
|
|
1183
1184
|
|
1184
1185
|
```ruby
|
1185
1186
|
create_table :versions do |t|
|
1186
|
-
...
|
1187
|
+
# ...
|
1187
1188
|
t.json :object # Full object changes
|
1188
1189
|
t.json :object_changes # Optional column-level changes
|
1189
|
-
...
|
1190
|
+
# ...
|
1190
1191
|
end
|
1191
1192
|
```
|
1192
1193
|
|
@@ -1331,13 +1332,13 @@ ENV["RAILS_ENV"] ||= 'test'
|
|
1331
1332
|
require 'spec_helper'
|
1332
1333
|
require File.expand_path("../../config/environment", __FILE__)
|
1333
1334
|
require 'rspec/rails'
|
1334
|
-
...
|
1335
|
+
# ...
|
1335
1336
|
require 'paper_trail/frameworks/rspec'
|
1336
1337
|
```
|
1337
1338
|
|
1338
1339
|
With the helper loaded, PaperTrail will be turned off for all tests by
|
1339
1340
|
default. To enable PaperTrail for a test you can either wrap the
|
1340
|
-
test in a `with_versioning` block, or pass in
|
1341
|
+
test in a `with_versioning` block, or pass in `versioning: true` option to a
|
1341
1342
|
spec block.
|
1342
1343
|
|
1343
1344
|
```ruby
|
@@ -1352,7 +1353,7 @@ describe "RSpec test group" do
|
|
1352
1353
|
end
|
1353
1354
|
end
|
1354
1355
|
|
1355
|
-
it 'can be turned on at the `it` or `describe` level
|
1356
|
+
it 'can be turned on at the `it` or `describe` level', versioning: true do
|
1356
1357
|
expect(PaperTrail).to be_enabled
|
1357
1358
|
end
|
1358
1359
|
end
|
@@ -1389,37 +1390,37 @@ describe Widget do
|
|
1389
1390
|
end
|
1390
1391
|
```
|
1391
1392
|
|
1392
|
-
|
1393
|
+
#### Matchers
|
1394
|
+
|
1395
|
+
The `have_a_version_with` matcher makes assertions about versions using
|
1396
|
+
`where_object`, based on the `object` column.
|
1393
1397
|
|
1394
1398
|
```ruby
|
1395
1399
|
describe '`have_a_version_with` matcher' do
|
1396
|
-
|
1400
|
+
it "is possible to do assertions on version attributes" do
|
1397
1401
|
widget.update_attributes!(name: 'Leonard', an_integer: 1)
|
1398
1402
|
widget.update_attributes!(name: 'Tom')
|
1399
1403
|
widget.update_attributes!(name: 'Bob')
|
1400
|
-
end
|
1401
|
-
|
1402
|
-
it "is possible to do assertions on version attributes" do
|
1403
1404
|
expect(widget).to have_a_version_with name: 'Leonard', an_integer: 1
|
1404
1405
|
expect(widget).to have_a_version_with an_integer: 1
|
1405
1406
|
expect(widget).to have_a_version_with name: 'Tom'
|
1406
1407
|
end
|
1407
1408
|
end
|
1408
1409
|
```
|
1409
|
-
|
1410
|
+
|
1411
|
+
The `have_a_version_with_changes` matcher makes assertions about versions using
|
1412
|
+
`where_object_changes`, based on the optional
|
1413
|
+
[`object_changes` column](#3c-diffing-versions).
|
1410
1414
|
|
1411
1415
|
```ruby
|
1412
1416
|
describe '`have_a_version_with_changes` matcher' do
|
1413
|
-
|
1417
|
+
it "is possible to do assertions on version changes" do
|
1414
1418
|
widget.update_attributes!(name: 'Leonard', an_integer: 1)
|
1415
1419
|
widget.update_attributes!(name: 'Tom')
|
1416
1420
|
widget.update_attributes!(name: 'Bob')
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
expect(widget).to have_a_version_with name: 'Leonard', an_integer: 2
|
1421
|
-
expect(widget).to have_a_version_with an_integer: 2
|
1422
|
-
expect(widget).to have_a_version_with name: 'Bob'
|
1421
|
+
expect(widget).to have_a_version_with_changes name: 'Leonard', an_integer: 2
|
1422
|
+
expect(widget).to have_a_version_with_changes an_integer: 2
|
1423
|
+
expect(widget).to have_a_version_with_changes name: 'Bob'
|
1423
1424
|
end
|
1424
1425
|
end
|
1425
1426
|
```
|
@@ -1430,7 +1431,7 @@ For more examples of the RSpec matchers, see the
|
|
1430
1431
|
### 7.c. Cucumber
|
1431
1432
|
|
1432
1433
|
PaperTrail provides a helper for [Cucumber][28] that works similar to the RSpec
|
1433
|
-
helper.If you
|
1434
|
+
helper. If you want to use the helper, you will need to require in your cucumber
|
1434
1435
|
helper like so:
|
1435
1436
|
|
1436
1437
|
```ruby
|
@@ -1438,12 +1439,12 @@ helper like so:
|
|
1438
1439
|
|
1439
1440
|
ENV["RAILS_ENV"] ||= "cucumber"
|
1440
1441
|
require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
|
1441
|
-
...
|
1442
|
+
# ...
|
1442
1443
|
require 'paper_trail/frameworks/cucumber'
|
1443
1444
|
```
|
1444
1445
|
|
1445
1446
|
When the helper is loaded, PaperTrail will be turned off for all scenarios by a
|
1446
|
-
`before` hook added by the helper by default. When you
|
1447
|
+
`before` hook added by the helper by default. When you want to enable PaperTrail
|
1447
1448
|
for a scenario, you can wrap code in a `with_versioning` block in a step, like
|
1448
1449
|
so:
|
1449
1450
|
|
@@ -1462,7 +1463,7 @@ value to `{}` as well, again, to help prevent data spillover between tests.
|
|
1462
1463
|
|
1463
1464
|
### 7.d. Spork
|
1464
1465
|
|
1465
|
-
If you
|
1466
|
+
If you want to use the `RSpec` or `Cucumber` helpers with [Spork][29], you will
|
1466
1467
|
need to manually require the helper(s) in your `prefork` block on your test
|
1467
1468
|
helper, like so:
|
1468
1469
|
|
@@ -1479,13 +1480,13 @@ Spork.prefork do
|
|
1479
1480
|
require 'rspec/rails'
|
1480
1481
|
require 'paper_trail/frameworks/rspec'
|
1481
1482
|
require 'paper_trail/frameworks/cucumber'
|
1482
|
-
...
|
1483
|
+
# ...
|
1483
1484
|
end
|
1484
1485
|
```
|
1485
1486
|
|
1486
1487
|
### 7.e. Zeus or Spring
|
1487
1488
|
|
1488
|
-
If you
|
1489
|
+
If you want to use the `RSpec` or `Cucumber` helpers with [Zeus][30] or
|
1489
1490
|
[Spring][31], you will need to manually require the helper(s) in your test
|
1490
1491
|
helper, like so:
|
1491
1492
|
|
@@ -6,6 +6,14 @@ module PaperTrail
|
|
6
6
|
class InstallGenerator < ::Rails::Generators::Base
|
7
7
|
include ::Rails::Generators::Migration
|
8
8
|
|
9
|
+
# Class names of MySQL adapters.
|
10
|
+
# - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`.
|
11
|
+
# - `Mysql2Adapter` - Used by `mysql2` gem.
|
12
|
+
MYSQL_ADAPTERS = [
|
13
|
+
"ActiveRecord::ConnectionAdapters::MysqlAdapter",
|
14
|
+
"ActiveRecord::ConnectionAdapters::Mysql2Adapter"
|
15
|
+
].freeze
|
16
|
+
|
9
17
|
source_root File.expand_path("../templates", __FILE__)
|
10
18
|
class_option(
|
11
19
|
:with_changes,
|
@@ -50,7 +58,57 @@ module PaperTrail
|
|
50
58
|
if self.class.migration_exists?(migration_dir, template)
|
51
59
|
::Kernel.warn "Migration already exists: #{template}"
|
52
60
|
else
|
53
|
-
migration_template
|
61
|
+
migration_template(
|
62
|
+
"#{template}.rb.erb",
|
63
|
+
"db/migrate/#{template}.rb",
|
64
|
+
item_type_options: item_type_options,
|
65
|
+
migration_version: migration_version,
|
66
|
+
versions_table_options: versions_table_options
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# MySQL 5.6 utf8mb4 limit is 191 chars for keys used in indexes.
|
74
|
+
# See https://github.com/airblade/paper_trail/issues/651
|
75
|
+
def item_type_options
|
76
|
+
opt = { null: false }
|
77
|
+
opt[:limit] = 191 if mysql?
|
78
|
+
", #{opt}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def migration_version
|
82
|
+
major = ActiveRecord::VERSION::MAJOR
|
83
|
+
if major >= 5
|
84
|
+
"[#{major}.#{ActiveRecord::VERSION::MINOR}]"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def mysql?
|
89
|
+
MYSQL_ADAPTERS.include?(ActiveRecord::Base.connection.class.name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Even modern versions of MySQL still use `latin1` as the default character
|
93
|
+
# encoding. Many users are not aware of this, and run into trouble when they
|
94
|
+
# try to use PaperTrail in apps that otherwise tend to use UTF-8. Postgres, by
|
95
|
+
# comparison, uses UTF-8 except in the unusual case where the OS is configured
|
96
|
+
# with a custom locale.
|
97
|
+
#
|
98
|
+
# - https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html
|
99
|
+
# - http://www.postgresql.org/docs/9.4/static/multibyte.html
|
100
|
+
#
|
101
|
+
# Furthermore, MySQL's original implementation of UTF-8 was flawed, and had
|
102
|
+
# to be fixed later by introducing a new charset, `utf8mb4`.
|
103
|
+
#
|
104
|
+
# - https://mathiasbynens.be/notes/mysql-utf8mb4
|
105
|
+
# - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
|
106
|
+
#
|
107
|
+
def versions_table_options
|
108
|
+
if mysql?
|
109
|
+
', { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }'
|
110
|
+
else
|
111
|
+
""
|
54
112
|
end
|
55
113
|
end
|
56
114
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# This migration creates the `versions` table, the only schema PT requires.
|
2
|
+
# All other migrations PT provides are optional.
|
3
|
+
class CreateVersions < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
|
5
|
+
# The largest text column available in all supported RDBMS is
|
6
|
+
# 1024^3 - 1 bytes, roughly one gibibyte. We specify a size
|
7
|
+
# so that MySQL will use `longtext` instead of `text`. Otherwise,
|
8
|
+
# when serializing very large objects, `text` might not be big enough.
|
9
|
+
TEXT_BYTES = 1_073_741_823
|
10
|
+
|
11
|
+
def change
|
12
|
+
create_table :versions<%= versions_table_options %> do |t|
|
13
|
+
t.string :item_type<%= item_type_options %>
|
14
|
+
t.integer :item_id, null: false
|
15
|
+
t.string :event, null: false
|
16
|
+
t.string :whodunnit
|
17
|
+
t.text :object, limit: TEXT_BYTES
|
18
|
+
|
19
|
+
# Known issue in MySQL: fractional second precision
|
20
|
+
# -------------------------------------------------
|
21
|
+
#
|
22
|
+
# MySQL timestamp columns do not support fractional seconds unless
|
23
|
+
# defined with "fractional seconds precision". MySQL users should manually
|
24
|
+
# add fractional seconds precision to this migration, specifically, to
|
25
|
+
# the `created_at` column.
|
26
|
+
# (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html)
|
27
|
+
#
|
28
|
+
# MySQL users should also upgrade to rails 4.2, which is the first
|
29
|
+
# version of ActiveRecord with support for fractional seconds in MySQL.
|
30
|
+
# (https://github.com/rails/rails/pull/14359)
|
31
|
+
#
|
32
|
+
t.datetime :created_at
|
33
|
+
end
|
34
|
+
add_index :versions, %i(item_type item_id)
|
35
|
+
end
|
36
|
+
end
|
data/paper_trail.gemspec
CHANGED
@@ -41,7 +41,7 @@ has been destroyed.
|
|
41
41
|
s.add_development_dependency "generator_spec", "~> 0.9.3"
|
42
42
|
s.add_development_dependency "database_cleaner", "~> 1.2"
|
43
43
|
s.add_development_dependency "pry-nav", "~> 0.2.4"
|
44
|
-
s.add_development_dependency "rubocop", "
|
44
|
+
s.add_development_dependency "rubocop", "0.48.0"
|
45
45
|
s.add_development_dependency "rubocop-rspec", "~> 1.15.0"
|
46
46
|
s.add_development_dependency "timecop", "~> 0.8.0"
|
47
47
|
s.add_development_dependency "sqlite3", "~> 1.2"
|
@@ -15,14 +15,30 @@ RSpec.describe PaperTrail::InstallGenerator, type: :generator do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "generates a migration for creating the 'versions' table" do
|
18
|
+
expected_parent_class = lambda {
|
19
|
+
old_school = "ActiveRecord::Migration"
|
20
|
+
ar_version = ActiveRecord::VERSION
|
21
|
+
if ar_version::MAJOR >= 5
|
22
|
+
format("%s[%d.%d]", old_school, ar_version::MAJOR, ar_version::MINOR)
|
23
|
+
else
|
24
|
+
old_school
|
25
|
+
end
|
26
|
+
}.call
|
27
|
+
expected_create_table_options = lambda {
|
28
|
+
if described_class::MYSQL_ADAPTERS.include?(ActiveRecord::Base.connection.class.name)
|
29
|
+
', { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }'
|
30
|
+
else
|
31
|
+
""
|
32
|
+
end
|
33
|
+
}.call
|
18
34
|
expect(destination_root).to(
|
19
35
|
have_structure {
|
20
36
|
directory("db") {
|
21
37
|
directory("migrate") {
|
22
38
|
migration("create_versions") {
|
23
|
-
contains
|
39
|
+
contains("class CreateVersions < " + expected_parent_class)
|
24
40
|
contains "def change"
|
25
|
-
contains "create_table :versions"
|
41
|
+
contains "create_table :versions#{expected_create_table_options}"
|
26
42
|
}
|
27
43
|
}
|
28
44
|
}
|
data/spec/models/boolit_spec.rb
CHANGED
@@ -1,48 +1,40 @@
|
|
1
1
|
require "rails_helper"
|
2
2
|
require Rails.root.join("..", "custom_json_serializer")
|
3
3
|
|
4
|
-
describe Boolit, type: :model do
|
5
|
-
|
4
|
+
RSpec.describe Boolit, type: :model, versioning: true do
|
5
|
+
subject { Boolit.create! }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
before { subject.update_attributes!(name: FFaker::Name.name) }
|
8
|
+
|
9
|
+
it "has two versions" do
|
10
|
+
expect(subject.versions.size).to eq(2)
|
9
11
|
end
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
+
it "can be reified and persisted" do
|
14
|
+
expect { subject.versions.last.reify.save! }.not_to raise_error
|
15
|
+
end
|
13
16
|
|
14
|
-
|
17
|
+
context "Instance falls out of default scope" do
|
18
|
+
before { subject.update_attributes!(scoped: false) }
|
15
19
|
|
16
|
-
it "
|
17
|
-
expect(
|
20
|
+
it "is NOT scoped" do
|
21
|
+
expect(Boolit.first).to be_nil
|
18
22
|
end
|
19
23
|
|
20
|
-
it "can be reified and persisted" do
|
21
|
-
expect { subject.
|
24
|
+
it "still can be reified and persisted" do
|
25
|
+
expect { subject.paper_trail.previous_version.save! }.not_to raise_error
|
22
26
|
end
|
23
27
|
|
24
|
-
context "
|
25
|
-
before
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
it "still can be reified and persisted" do
|
32
|
-
expect { subject.paper_trail.previous_version.save! }.not_to raise_error
|
28
|
+
context "with `nil` attributes on the live instance" do
|
29
|
+
before do
|
30
|
+
PaperTrail.serializer = CustomJsonSerializer
|
31
|
+
subject.update_attributes!(name: nil)
|
32
|
+
subject.update_attributes!(name: FFaker::Name.name)
|
33
33
|
end
|
34
|
+
after { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
PaperTrail.serializer = CustomJsonSerializer
|
38
|
-
subject.update_attributes!(name: nil)
|
39
|
-
subject.update_attributes!(name: FFaker::Name.name)
|
40
|
-
end
|
41
|
-
after { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
42
|
-
|
43
|
-
it "does not overwrite that attribute during the reification process" do
|
44
|
-
expect(subject.paper_trail.previous_version.name).to be_nil
|
45
|
-
end
|
36
|
+
it "does not overwrite that attribute during the reification process" do
|
37
|
+
expect(subject.paper_trail.previous_version.name).to be_nil
|
46
38
|
end
|
47
39
|
end
|
48
40
|
end
|