paper_trail 7.0.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3a67c57c19665911311eab6dc66bd670e390f57
4
- data.tar.gz: f74e8562ba1ac3e305d5785e50fc1357ee0a69ca
3
+ metadata.gz: 4e92a25394990bd883a845f051763e117abd5d35
4
+ data.tar.gz: bde729a85a1052106a116e930f3afafdde5ca319
5
5
  SHA512:
6
- metadata.gz: 8e493b2ef87fb52d53c54cefa55369ee31ac82261d30dac5833bc4d010aeff5387fd9362deef390b97e7b646bc22fbbaeb5ea2620d63cc2369e5e9ddcd78744e
7
- data.tar.gz: 4cb5a0c791d890011e9aff19d0e8119955e43d8aab22a2bd57f5c7c9457dd5dc60345d79494aedf87e254dd3dde524832b04e2baeeca4eaedc1b7e1f91b5b893
6
+ metadata.gz: 7f2d6eba98c56942424310f2a3cc0c855c264eecc17fa0377dbb4bdad0ed0e15d66190e1043671af4c2f35c9605f0707565bdada142c1a5f8ce6b3eac203c8e3
7
+ data.tar.gz: 99b7dd59468398c88e7c15f4e8b4fa6a2ba274a1aa8794a2caa8351d54cf6abdc51908449d26e71382b0505f08bcd0cdfbaa8fa2a030f9a76a391e84daafc8db
data/.rubocop_todo.yml CHANGED
@@ -27,8 +27,5 @@ RSpec/MessageSpies:
27
27
  RSpec/NamedSubject:
28
28
  Enabled: false
29
29
 
30
- RSpec/NestedGroups:
31
- Max: 5 # goal: 3
32
-
33
30
  Security/YAMLLoad:
34
31
  Enabled: false
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.0 | https://github.com/airblade/paper_trail/blob/v7.0.0/README.md |
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 wish to selectively record changes for some models but not others 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 `:versioning => true` option to a
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 like this', :versioning => true do
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
- It is also possible to do assertions on the versions using `have_a_version_with` matcher.
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
- before do
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
- There is also a `have_a_version_with_changes` matcher. This is only usable if your versions table [has an `object_changes` column for storing changesets](#3c-diffing-versions).
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
- before do
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
- end
1418
-
1419
- it "is possible to do assertions on version changes" do
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 wish to use the helper, you will need to require in your cucumber
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 wish to enable PaperTrail
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 wish to use the `RSpec` or `Cucumber` helpers with [Spork][29], you will
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 wish to use the `RSpec` or `Cucumber` helpers with [Zeus][30] or
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 "#{template}.rb", "db/migrate/#{template}.rb"
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
@@ -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
@@ -7,7 +7,7 @@ module PaperTrail
7
7
  module VERSION
8
8
  MAJOR = 7
9
9
  MINOR = 0
10
- TINY = 0
10
+ TINY = 1
11
11
  PRE = nil
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".").freeze
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", "~> 0.48.0"
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 "class CreateVersions"
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
  }
@@ -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
- it { is_expected.to be_versioned }
4
+ RSpec.describe Boolit, type: :model, versioning: true do
5
+ subject { Boolit.create! }
6
6
 
7
- it "has a default scope" do
8
- expect(subject.default_scopes).not_to be_empty
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
- describe "Versioning", versioning: true do
12
- subject { Boolit.create! }
13
+ it "can be reified and persisted" do
14
+ expect { subject.versions.last.reify.save! }.not_to raise_error
15
+ end
13
16
 
14
- before { subject.update_attributes!(name: FFaker::Name.name) }
17
+ context "Instance falls out of default scope" do
18
+ before { subject.update_attributes!(scoped: false) }
15
19
 
16
- it "has two versions" do
17
- expect(subject.versions.size).to eq(2)
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.versions.last.reify.save! }.not_to raise_error
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 "Instance falls out of default scope" do
25
- before { subject.update_attributes!(scoped: false) }
26
-
27
- it "is NOT scoped" do
28
- expect(Boolit.first).to be_nil
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
- context "with `nil` attributes on the live instance" do
36
- before do
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