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 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