paper_trail 5.2.3 → 11.0.0
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 +5 -5
- data/lib/generators/paper_trail/install/USAGE +3 -0
- data/lib/generators/paper_trail/install/install_generator.rb +75 -0
- data/lib/generators/paper_trail/{templates/add_object_changes_to_versions.rb → install/templates/add_object_changes_to_versions.rb.erb} +1 -1
- data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +36 -0
- data/lib/generators/paper_trail/migration_generator.rb +38 -0
- data/lib/generators/paper_trail/update_item_subtype/USAGE +4 -0
- data/lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb +85 -0
- data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +17 -0
- data/lib/paper_trail.rb +82 -130
- data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +27 -0
- data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +15 -44
- data/lib/paper_trail/attribute_serializers/object_attribute.rb +2 -0
- data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +2 -0
- data/lib/paper_trail/cleaner.rb +3 -1
- data/lib/paper_trail/compatibility.rb +51 -0
- data/lib/paper_trail/config.rb +11 -49
- data/lib/paper_trail/events/base.rb +323 -0
- data/lib/paper_trail/events/create.rb +32 -0
- data/lib/paper_trail/events/destroy.rb +42 -0
- data/lib/paper_trail/events/update.rb +60 -0
- data/lib/paper_trail/frameworks/active_record.rb +2 -1
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +8 -3
- data/lib/paper_trail/frameworks/cucumber.rb +5 -3
- data/lib/paper_trail/frameworks/rails.rb +2 -0
- data/lib/paper_trail/frameworks/rails/controller.rb +33 -43
- data/lib/paper_trail/frameworks/rails/engine.rb +34 -1
- data/lib/paper_trail/frameworks/rspec.rb +17 -4
- data/lib/paper_trail/frameworks/rspec/helpers.rb +2 -0
- data/lib/paper_trail/has_paper_trail.rb +22 -310
- data/lib/paper_trail/model_config.rb +157 -109
- data/lib/paper_trail/queries/versions/where_object.rb +65 -0
- data/lib/paper_trail/queries/versions/where_object_changes.rb +75 -0
- data/lib/paper_trail/record_history.rb +3 -9
- data/lib/paper_trail/record_trail.rb +169 -319
- data/lib/paper_trail/reifier.rb +53 -374
- data/lib/paper_trail/request.rb +166 -0
- data/lib/paper_trail/serializers/json.rb +9 -10
- data/lib/paper_trail/serializers/yaml.rb +15 -28
- data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +48 -0
- data/lib/paper_trail/version_concern.rb +160 -155
- data/lib/paper_trail/version_number.rb +12 -4
- metadata +77 -372
- data/.github/CONTRIBUTING.md +0 -109
- data/.github/ISSUE_TEMPLATE.md +0 -13
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.rubocop.yml +0 -99
- data/.rubocop_todo.yml +0 -22
- data/.travis.yml +0 -41
- data/Appraisals +0 -38
- data/CHANGELOG.md +0 -560
- data/Gemfile +0 -2
- data/MIT-LICENSE +0 -20
- data/README.md +0 -1654
- data/Rakefile +0 -30
- data/doc/bug_report_template.rb +0 -69
- data/doc/warning_about_not_setting_whodunnit.md +0 -32
- data/gemfiles/ar3.gemfile +0 -19
- data/gemfiles/ar4.gemfile +0 -8
- data/gemfiles/ar5.gemfile +0 -9
- data/lib/generators/paper_trail/USAGE +0 -2
- data/lib/generators/paper_trail/default_initializer.rb +0 -0
- data/lib/generators/paper_trail/install_generator.rb +0 -57
- data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +0 -13
- data/lib/generators/paper_trail/templates/create_version_associations.rb +0 -22
- data/lib/generators/paper_trail/templates/create_versions.rb +0 -80
- data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +0 -48
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +0 -11
- data/lib/paper_trail/frameworks/sinatra.rb +0 -40
- data/lib/paper_trail/version_association_concern.rb +0 -17
- data/paper_trail.gemspec +0 -56
- data/spec/generators/install_generator_spec.rb +0 -66
- data/spec/generators/paper_trail/templates/create_versions_spec.rb +0 -51
- data/spec/models/animal_spec.rb +0 -36
- data/spec/models/boolit_spec.rb +0 -48
- data/spec/models/callback_modifier_spec.rb +0 -96
- data/spec/models/car_spec.rb +0 -13
- data/spec/models/custom_primary_key_record_spec.rb +0 -18
- data/spec/models/fluxor_spec.rb +0 -17
- data/spec/models/gadget_spec.rb +0 -68
- data/spec/models/joined_version_spec.rb +0 -47
- data/spec/models/json_version_spec.rb +0 -102
- data/spec/models/kitchen/banana_spec.rb +0 -14
- data/spec/models/not_on_update_spec.rb +0 -22
- data/spec/models/post_with_status_spec.rb +0 -50
- data/spec/models/skipper_spec.rb +0 -46
- data/spec/models/thing_spec.rb +0 -11
- data/spec/models/truck_spec.rb +0 -5
- data/spec/models/vehicle_spec.rb +0 -5
- data/spec/models/version_spec.rb +0 -272
- data/spec/models/widget_spec.rb +0 -343
- data/spec/modules/paper_trail_spec.rb +0 -27
- data/spec/modules/version_concern_spec.rb +0 -31
- data/spec/modules/version_number_spec.rb +0 -43
- data/spec/paper_trail/config_spec.rb +0 -33
- data/spec/paper_trail_spec.rb +0 -79
- data/spec/rails_helper.rb +0 -34
- data/spec/requests/articles_spec.rb +0 -34
- data/spec/spec_helper.rb +0 -114
- data/spec/support/alt_db_init.rb +0 -54
- data/test/custom_json_serializer.rb +0 -13
- data/test/dummy/Rakefile +0 -7
- data/test/dummy/app/controllers/application_controller.rb +0 -33
- data/test/dummy/app/controllers/articles_controller.rb +0 -20
- data/test/dummy/app/controllers/test_controller.rb +0 -5
- data/test/dummy/app/controllers/widgets_controller.rb +0 -32
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/models/animal.rb +0 -6
- data/test/dummy/app/models/article.rb +0 -24
- data/test/dummy/app/models/authorship.rb +0 -5
- data/test/dummy/app/models/bar_habtm.rb +0 -4
- data/test/dummy/app/models/book.rb +0 -9
- data/test/dummy/app/models/boolit.rb +0 -4
- data/test/dummy/app/models/callback_modifier.rb +0 -45
- data/test/dummy/app/models/car.rb +0 -3
- data/test/dummy/app/models/cat.rb +0 -2
- data/test/dummy/app/models/chapter.rb +0 -9
- data/test/dummy/app/models/citation.rb +0 -5
- data/test/dummy/app/models/custom_primary_key_record.rb +0 -13
- data/test/dummy/app/models/customer.rb +0 -4
- data/test/dummy/app/models/document.rb +0 -4
- data/test/dummy/app/models/dog.rb +0 -2
- data/test/dummy/app/models/editor.rb +0 -4
- data/test/dummy/app/models/editorship.rb +0 -5
- data/test/dummy/app/models/elephant.rb +0 -3
- data/test/dummy/app/models/fluxor.rb +0 -3
- data/test/dummy/app/models/foo_habtm.rb +0 -5
- data/test/dummy/app/models/foo_widget.rb +0 -2
- data/test/dummy/app/models/fruit.rb +0 -5
- data/test/dummy/app/models/gadget.rb +0 -3
- data/test/dummy/app/models/kitchen/banana.rb +0 -5
- data/test/dummy/app/models/legacy_widget.rb +0 -4
- data/test/dummy/app/models/line_item.rb +0 -4
- data/test/dummy/app/models/not_on_update.rb +0 -4
- data/test/dummy/app/models/order.rb +0 -5
- data/test/dummy/app/models/paragraph.rb +0 -5
- data/test/dummy/app/models/person.rb +0 -38
- data/test/dummy/app/models/post.rb +0 -3
- data/test/dummy/app/models/post_with_status.rb +0 -8
- data/test/dummy/app/models/protected_widget.rb +0 -3
- data/test/dummy/app/models/quotation.rb +0 -5
- data/test/dummy/app/models/section.rb +0 -6
- data/test/dummy/app/models/skipper.rb +0 -6
- data/test/dummy/app/models/song.rb +0 -41
- data/test/dummy/app/models/thing.rb +0 -3
- data/test/dummy/app/models/translation.rb +0 -4
- data/test/dummy/app/models/truck.rb +0 -4
- data/test/dummy/app/models/vehicle.rb +0 -4
- data/test/dummy/app/models/whatchamajigger.rb +0 -4
- data/test/dummy/app/models/widget.rb +0 -16
- data/test/dummy/app/models/wotsit.rb +0 -8
- data/test/dummy/app/versions/custom_primary_key_record_version.rb +0 -3
- data/test/dummy/app/versions/joined_version.rb +0 -6
- data/test/dummy/app/versions/json_version.rb +0 -3
- data/test/dummy/app/versions/kitchen/banana_version.rb +0 -5
- data/test/dummy/app/versions/post_version.rb +0 -3
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/config.ru +0 -4
- data/test/dummy/config/application.rb +0 -80
- data/test/dummy/config/boot.rb +0 -10
- data/test/dummy/config/database.mysql.yml +0 -19
- data/test/dummy/config/database.postgres.yml +0 -15
- data/test/dummy/config/database.sqlite.yml +0 -15
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -41
- data/test/dummy/config/environments/production.rb +0 -74
- data/test/dummy/config/environments/test.rb +0 -51
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/test/dummy/config/initializers/inflections.rb +0 -10
- data/test/dummy/config/initializers/mime_types.rb +0 -5
- data/test/dummy/config/initializers/paper_trail.rb +0 -9
- data/test/dummy/config/initializers/secret_token.rb +0 -9
- data/test/dummy/config/initializers/session_store.rb +0 -8
- data/test/dummy/config/locales/en.yml +0 -5
- data/test/dummy/config/routes.rb +0 -4
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +0 -361
- data/test/dummy/db/schema.rb +0 -288
- data/test/dummy/script/rails +0 -8
- data/test/functional/controller_test.rb +0 -90
- data/test/functional/enabled_for_controller_test.rb +0 -28
- data/test/functional/modular_sinatra_test.rb +0 -46
- data/test/functional/sinatra_test.rb +0 -51
- data/test/functional/thread_safety_test.rb +0 -46
- data/test/test_helper.rb +0 -127
- data/test/time_travel_helper.rb +0 -1
- data/test/unit/associations_test.rb +0 -1016
- data/test/unit/cleaner_test.rb +0 -188
- data/test/unit/inheritance_column_test.rb +0 -43
- data/test/unit/model_test.rb +0 -1489
- data/test/unit/protected_attrs_test.rb +0 -52
- data/test/unit/serializer_test.rb +0 -119
- data/test/unit/serializers/json_test.rb +0 -95
- data/test/unit/serializers/mixin_json_test.rb +0 -37
- data/test/unit/serializers/mixin_yaml_test.rb +0 -53
- data/test/unit/serializers/yaml_test.rb +0 -54
- data/test/unit/timestamp_test.rb +0 -41
- data/test/unit/version_test.rb +0 -119
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f8f7237a39b0645932b394ee0332846be680f6a725ed02c7a126aa892d840ccc
|
4
|
+
data.tar.gz: b0356d622a6e6f3ba0938c4d9fe0ff211b347a0c65e2d3a6574bc8bf5fb04df6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46ad3d73231d4ab6c3d978925e7b838af2697b2b998b9a7948d078266fbdbec33b6dbdcbfb93751f2aa961be6a3499f499a71d56e3fbc6138174cb752feae41a
|
7
|
+
data.tar.gz: 9ec2fc044229898aa2c5ab70dc41b549b6896c61af42633af0760e6b99aadd375f5f7e39160ad713131ecb439b0f5aff8cb6696f276f4c5225eb40e371f43035
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../migration_generator"
|
4
|
+
|
5
|
+
module PaperTrail
|
6
|
+
# Installs PaperTrail in a rails app.
|
7
|
+
class InstallGenerator < MigrationGenerator
|
8
|
+
# Class names of MySQL adapters.
|
9
|
+
# - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`.
|
10
|
+
# - `Mysql2Adapter` - Used by `mysql2` gem.
|
11
|
+
MYSQL_ADAPTERS = [
|
12
|
+
"ActiveRecord::ConnectionAdapters::MysqlAdapter",
|
13
|
+
"ActiveRecord::ConnectionAdapters::Mysql2Adapter"
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
source_root File.expand_path("templates", __dir__)
|
17
|
+
class_option(
|
18
|
+
:with_changes,
|
19
|
+
type: :boolean,
|
20
|
+
default: false,
|
21
|
+
desc: "Store changeset (diff) with each version"
|
22
|
+
)
|
23
|
+
|
24
|
+
desc "Generates (but does not run) a migration to add a versions table." \
|
25
|
+
" See section 5.c. Generators in README.md for more information."
|
26
|
+
|
27
|
+
def create_migration_file
|
28
|
+
add_paper_trail_migration(
|
29
|
+
"create_versions",
|
30
|
+
item_type_options: item_type_options,
|
31
|
+
versions_table_options: versions_table_options
|
32
|
+
)
|
33
|
+
if options.with_changes?
|
34
|
+
add_paper_trail_migration("add_object_changes_to_versions")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# MySQL 5.6 utf8mb4 limit is 191 chars for keys used in indexes.
|
41
|
+
# See https://github.com/paper-trail-gem/paper_trail/issues/651
|
42
|
+
def item_type_options
|
43
|
+
opt = { null: false }
|
44
|
+
opt[:limit] = 191 if mysql?
|
45
|
+
", #{opt}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def mysql?
|
49
|
+
MYSQL_ADAPTERS.include?(ActiveRecord::Base.connection.class.name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Even modern versions of MySQL still use `latin1` as the default character
|
53
|
+
# encoding. Many users are not aware of this, and run into trouble when they
|
54
|
+
# try to use PaperTrail in apps that otherwise tend to use UTF-8. Postgres, by
|
55
|
+
# comparison, uses UTF-8 except in the unusual case where the OS is configured
|
56
|
+
# with a custom locale.
|
57
|
+
#
|
58
|
+
# - https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html
|
59
|
+
# - http://www.postgresql.org/docs/9.4/static/multibyte.html
|
60
|
+
#
|
61
|
+
# Furthermore, MySQL's original implementation of UTF-8 was flawed, and had
|
62
|
+
# to be fixed later by introducing a new charset, `utf8mb4`.
|
63
|
+
#
|
64
|
+
# - https://mathiasbynens.be/notes/mysql-utf8mb4
|
65
|
+
# - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
|
66
|
+
#
|
67
|
+
def versions_table_options
|
68
|
+
if mysql?
|
69
|
+
', { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }'
|
70
|
+
else
|
71
|
+
""
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# This migration adds the optional `object_changes` column, in which PaperTrail
|
2
2
|
# will store the `changes` diff for each update event. See the readme for
|
3
3
|
# details.
|
4
|
-
class AddObjectChangesToVersions < ActiveRecord::Migration
|
4
|
+
class AddObjectChangesToVersions < ActiveRecord::Migration<%= migration_version %>
|
5
5
|
# The largest text column available in all supported RDBMS.
|
6
6
|
# See `create_versions.rb` for details.
|
7
7
|
TEXT_BYTES = 1_073_741_823
|
@@ -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.bigint :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 at least 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
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
require "rails/generators/active_record"
|
5
|
+
|
6
|
+
module PaperTrail
|
7
|
+
# Basic structure to support a generator that builds a migration
|
8
|
+
class MigrationGenerator < ::Rails::Generators::Base
|
9
|
+
include ::Rails::Generators::Migration
|
10
|
+
|
11
|
+
def self.next_migration_number(dirname)
|
12
|
+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def add_paper_trail_migration(template, extra_options = {})
|
18
|
+
migration_dir = File.expand_path("db/migrate")
|
19
|
+
if self.class.migration_exists?(migration_dir, template)
|
20
|
+
::Kernel.warn "Migration already exists: #{template}"
|
21
|
+
else
|
22
|
+
migration_template(
|
23
|
+
"#{template}.rb.erb",
|
24
|
+
"db/migrate/#{template}.rb",
|
25
|
+
{ migration_version: migration_version }.merge(extra_options)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def migration_version
|
31
|
+
format(
|
32
|
+
"[%d.%d]",
|
33
|
+
ActiveRecord::VERSION::MAJOR,
|
34
|
+
ActiveRecord::VERSION::MINOR
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# This migration updates existing `versions` that have `item_type` that refers to
|
2
|
+
# the base_class, and changes them to refer to the subclass instead.
|
3
|
+
class UpdateVersionsForItemSubtype < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
include ActionView::Helpers::TextHelper
|
5
|
+
def up
|
6
|
+
<%=
|
7
|
+
# Returns class, column, range
|
8
|
+
def self.parse_custom_entry(text)
|
9
|
+
parts = text.split("):")
|
10
|
+
range = parts.last.split("..").map(&:to_i)
|
11
|
+
range = Range.new(range.first, range.last)
|
12
|
+
parts.first.split("(") + [range]
|
13
|
+
end
|
14
|
+
# Running:
|
15
|
+
# rails g paper_trail:update_item_subtype Animal(species):1..4 Plant(genus):42..1337
|
16
|
+
# results in:
|
17
|
+
# # Versions of item_type "Animal" with IDs between 1 and 4 will be updated based on `species`
|
18
|
+
# # Versions of item_type "Plant" with IDs between 42 and 1337 will be updated based on `genus`
|
19
|
+
# hints = {"Animal"=>{1..4=>"species"}, "Plant"=>{42..1337=>"genus"}}
|
20
|
+
hint_descriptions = ""
|
21
|
+
hints = args.inject(Hash.new{|h, k| h[k] = {}}) do |s, v|
|
22
|
+
klass, column, range = parse_custom_entry(v)
|
23
|
+
hint_descriptions << " # Versions of item_type \"#{klass}\" with IDs between #{
|
24
|
+
range.first} and #{range.last} will be updated based on \`#{column}\`\n"
|
25
|
+
s[klass][range] = column
|
26
|
+
s
|
27
|
+
end
|
28
|
+
|
29
|
+
unless hints.empty?
|
30
|
+
"#{hint_descriptions} hints = #{hints.inspect}\n"
|
31
|
+
end
|
32
|
+
%>
|
33
|
+
# Find all ActiveRecord models mentioned in existing versions
|
34
|
+
changes = Hash.new { |h, k| h[k] = [] }
|
35
|
+
model_names = PaperTrail::Version.select(:item_type).distinct
|
36
|
+
model_names.map(&:item_type).each do |model_name|
|
37
|
+
hint = hints[model_name] if defined?(hints)
|
38
|
+
begin
|
39
|
+
klass = model_name.constantize
|
40
|
+
# Actually implements an inheritance_column? (Usually "type")
|
41
|
+
has_inheritance_column = klass.columns.map(&:name).include?(klass.inheritance_column)
|
42
|
+
# Find domain of types stored in PaperTrail versions
|
43
|
+
PaperTrail::Version.where(item_type: model_name, item_subtype: nil).select(:id, :object, :object_changes).each do |obj|
|
44
|
+
if (object_detail = PaperTrail.serializer.load(obj.object || obj.object_changes))
|
45
|
+
is_found = false
|
46
|
+
subtype_name = nil
|
47
|
+
hint&.each do |k, v|
|
48
|
+
if k === obj.id && (subtype_name = object_detail[v])
|
49
|
+
break
|
50
|
+
end
|
51
|
+
end
|
52
|
+
if subtype_name.nil? && has_inheritance_column
|
53
|
+
subtype_name = object_detail[klass.inheritance_column]
|
54
|
+
end
|
55
|
+
if subtype_name
|
56
|
+
subtype_name = subtype_name.last if subtype_name.is_a?(Array)
|
57
|
+
if subtype_name != model_name
|
58
|
+
changes[subtype_name] << obj.id
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
rescue NameError => ex
|
64
|
+
say "Skipping reference to #{model_name}", subitem: true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
changes.each do |k, v|
|
68
|
+
# Update in blocks of up to 100 at a time
|
69
|
+
block_of_ids = []
|
70
|
+
id_count = 0
|
71
|
+
num_updated = 0
|
72
|
+
v.sort.each do |id|
|
73
|
+
block_of_ids << id
|
74
|
+
if (id_count += 1) % 100 == 0
|
75
|
+
num_updated += PaperTrail::Version.where(id: block_of_ids).update_all(item_subtype: k)
|
76
|
+
block_of_ids = []
|
77
|
+
end
|
78
|
+
end
|
79
|
+
num_updated += PaperTrail::Version.where(id: block_of_ids).update_all(item_subtype: k)
|
80
|
+
if num_updated > 0
|
81
|
+
say "Associated #{pluralize(num_updated, 'record')} to #{k}", subitem: true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../migration_generator"
|
4
|
+
|
5
|
+
module PaperTrail
|
6
|
+
# Updates STI entries for PaperTrail
|
7
|
+
class UpdateItemSubtypeGenerator < MigrationGenerator
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
desc "Generates (but does not run) a migration to update item_subtype for STI entries in an "\
|
11
|
+
"existing versions table."
|
12
|
+
|
13
|
+
def create_migration_file
|
14
|
+
add_paper_trail_migration("update_versions_for_item_subtype", sti_type_options: options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/paper_trail.rb
CHANGED
@@ -1,10 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# AR does not require all of AS, but PT does. PT uses core_ext like
|
4
|
+
# `String#squish`, so we require `active_support/all`. Instead of eagerly
|
5
|
+
# loading all of AS here, we could put specific `require`s in only the various
|
6
|
+
# PT files that need them, but this seems easier to troubleshoot, though it may
|
7
|
+
# add a few milliseconds to rails boot time. If that becomes a pain point, we
|
8
|
+
# can revisit this decision.
|
9
|
+
require "active_support/all"
|
10
|
+
|
11
|
+
# AR is required for, eg. has_paper_trail.rb, so we could put this `require` in
|
12
|
+
# all of those files, but it seems easier to troubleshoot if we just make sure
|
13
|
+
# AR is loaded here before loading *any* of PT. See discussion of
|
14
|
+
# performance/simplicity tradeoff for activesupport above.
|
15
|
+
require "active_record"
|
16
|
+
|
1
17
|
require "request_store"
|
2
18
|
require "paper_trail/cleaner"
|
19
|
+
require "paper_trail/compatibility"
|
3
20
|
require "paper_trail/config"
|
4
21
|
require "paper_trail/has_paper_trail"
|
5
22
|
require "paper_trail/record_history"
|
6
23
|
require "paper_trail/reifier"
|
7
|
-
require "paper_trail/
|
24
|
+
require "paper_trail/request"
|
8
25
|
require "paper_trail/version_concern"
|
9
26
|
require "paper_trail/version_number"
|
10
27
|
require "paper_trail/serializers/json"
|
@@ -13,155 +30,88 @@ require "paper_trail/serializers/yaml"
|
|
13
30
|
# An ActiveRecord extension that tracks changes to your models, for auditing or
|
14
31
|
# versioning.
|
15
32
|
module PaperTrail
|
33
|
+
E_RAILS_NOT_LOADED = <<-EOS.squish.freeze
|
34
|
+
PaperTrail has been loaded too early, before rails is loaded. This can
|
35
|
+
happen when another gem defines the ::Rails namespace, then PT is loaded,
|
36
|
+
all before rails is loaded. You may want to reorder your Gemfile, or defer
|
37
|
+
the loading of PT by using `require: false` and a manual require elsewhere.
|
38
|
+
EOS
|
39
|
+
E_TIMESTAMP_FIELD_CONFIG = <<-EOS.squish.freeze
|
40
|
+
PaperTrail.timestamp_field= has been removed, without replacement. It is no
|
41
|
+
longer configurable. The timestamp column in the versions table must now be
|
42
|
+
named created_at.
|
43
|
+
EOS
|
44
|
+
|
16
45
|
extend PaperTrail::Cleaner
|
17
46
|
|
18
47
|
class << self
|
19
|
-
#
|
20
|
-
def clear_transaction_id
|
21
|
-
self.transaction_id = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
# Switches PaperTrail on or off.
|
48
|
+
# Switches PaperTrail on or off, for all threads.
|
25
49
|
# @api public
|
26
50
|
def enabled=(value)
|
27
51
|
PaperTrail.config.enabled = value
|
28
52
|
end
|
29
53
|
|
30
|
-
# Returns `true` if PaperTrail is on, `false` otherwise.
|
31
|
-
#
|
54
|
+
# Returns `true` if PaperTrail is on, `false` otherwise. This is the
|
55
|
+
# on/off switch that affects all threads. Enabled by default.
|
32
56
|
# @api public
|
33
57
|
def enabled?
|
34
58
|
!!PaperTrail.config.enabled
|
35
59
|
end
|
36
60
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
)
|
42
|
-
false
|
43
|
-
end
|
44
|
-
|
45
|
-
# Sets whether PaperTrail is enabled or disabled for the current request.
|
46
|
-
# @api public
|
47
|
-
def enabled_for_controller=(value)
|
48
|
-
paper_trail_store[:request_enabled_for_controller] = value
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns `true` if PaperTrail is enabled for the request, `false` otherwise.
|
61
|
+
# Returns PaperTrail's `::Gem::Version`, convenient for comparisons. This is
|
62
|
+
# recommended over `::PaperTrail::VERSION::STRING`.
|
63
|
+
#
|
64
|
+
# Added in 7.0.0
|
52
65
|
#
|
53
|
-
# See `PaperTrail::Rails::Controller#paper_trail_enabled_for_controller`.
|
54
|
-
# @api public
|
55
|
-
def enabled_for_controller?
|
56
|
-
!!paper_trail_store[:request_enabled_for_controller]
|
57
|
-
end
|
58
|
-
|
59
|
-
# Sets whether PaperTrail is enabled or disabled for this model in the
|
60
|
-
# current request.
|
61
66
|
# @api public
|
62
|
-
def
|
63
|
-
|
67
|
+
def gem_version
|
68
|
+
::Gem::Version.new(VERSION::STRING)
|
64
69
|
end
|
65
70
|
|
66
|
-
#
|
67
|
-
#
|
71
|
+
# Set variables for the current request, eg. whodunnit.
|
72
|
+
#
|
73
|
+
# All request-level variables are now managed here, as of PT 9. Having the
|
74
|
+
# word "request" right there in your application code will remind you that
|
75
|
+
# these variables only affect the current request, not all threads.
|
76
|
+
#
|
77
|
+
# Given a block, temporarily sets the given `options`, executes the block,
|
78
|
+
# and returns the value of the block.
|
79
|
+
#
|
80
|
+
# Without a block, this currently just returns `PaperTrail::Request`.
|
81
|
+
# However, please do not use `PaperTrail::Request` directly. Currently,
|
82
|
+
# `Request` is a `Module`, but in the future it is quite possible we may
|
83
|
+
# make it a `Class`. If we make such a choice, we will not provide any
|
84
|
+
# warning and will not treat it as a breaking change. You've been warned :)
|
85
|
+
#
|
68
86
|
# @api public
|
69
|
-
def
|
70
|
-
|
87
|
+
def request(options = nil, &block)
|
88
|
+
if options.nil? && !block_given?
|
89
|
+
Request
|
90
|
+
else
|
91
|
+
Request.with(options, &block)
|
92
|
+
end
|
71
93
|
end
|
72
94
|
|
73
95
|
# Set the field which records when a version was created.
|
74
96
|
# @api public
|
75
|
-
|
76
|
-
|
77
|
-
::ActiveSupport::Deprecation.warn(
|
78
|
-
"PaperTrail.timestamp_field= is deprecated without replacement." \
|
79
|
-
"See https://github.com/airblade/paper_trail/pull/861 for discussion",
|
80
|
-
caller(1)
|
81
|
-
)
|
82
|
-
PaperTrail.config.timestamp_field = field_name
|
83
|
-
end
|
84
|
-
|
85
|
-
# Returns the field which records when a version was created.
|
86
|
-
# @api public
|
87
|
-
# @deprecated
|
88
|
-
def timestamp_field
|
89
|
-
PaperTrail.config.timestamp_field
|
97
|
+
def timestamp_field=(_field_name)
|
98
|
+
raise(E_TIMESTAMP_FIELD_CONFIG)
|
90
99
|
end
|
91
100
|
|
92
|
-
#
|
93
|
-
# this in a migration or on the console, when working with models directly.
|
94
|
-
# In a controller it is set automatically to the `current_user`.
|
95
|
-
# @api public
|
96
|
-
def whodunnit=(value)
|
97
|
-
paper_trail_store[:whodunnit] = value
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns who is reponsible for any changes that occur.
|
101
|
-
# @api public
|
102
|
-
def whodunnit
|
103
|
-
paper_trail_store[:whodunnit]
|
104
|
-
end
|
105
|
-
|
106
|
-
# Sets any information from the controller that you want PaperTrail to
|
107
|
-
# store. By default this is set automatically by a before filter.
|
108
|
-
# @api public
|
109
|
-
def controller_info=(value)
|
110
|
-
paper_trail_store[:controller_info] = value
|
111
|
-
end
|
112
|
-
|
113
|
-
# Returns any information from the controller that you want
|
114
|
-
# PaperTrail to store.
|
115
|
-
#
|
116
|
-
# See `PaperTrail::Rails::Controller#info_for_paper_trail`.
|
117
|
-
# @api public
|
118
|
-
def controller_info
|
119
|
-
paper_trail_store[:controller_info]
|
120
|
-
end
|
121
|
-
|
122
|
-
# Getter and Setter for PaperTrail Serializer
|
101
|
+
# Set the PaperTrail serializer. This setting affects all threads.
|
123
102
|
# @api public
|
124
103
|
def serializer=(value)
|
125
104
|
PaperTrail.config.serializer = value
|
126
105
|
end
|
127
106
|
|
107
|
+
# Get the PaperTrail serializer used by all threads.
|
128
108
|
# @api public
|
129
109
|
def serializer
|
130
110
|
PaperTrail.config.serializer
|
131
111
|
end
|
132
112
|
|
133
|
-
# Returns
|
134
|
-
#
|
135
|
-
# whitelist_attributes, etc.
|
136
|
-
# @api public
|
137
|
-
def active_record_protected_attributes?
|
138
|
-
@active_record_protected_attributes ||= ::ActiveRecord::VERSION::MAJOR < 4 ||
|
139
|
-
!!defined?(ProtectedAttributes)
|
140
|
-
end
|
141
|
-
|
142
|
-
# @api public
|
143
|
-
def transaction?
|
144
|
-
::ActiveRecord::Base.connection.open_transactions > 0
|
145
|
-
end
|
146
|
-
|
147
|
-
# @api public
|
148
|
-
def transaction_id
|
149
|
-
paper_trail_store[:transaction_id]
|
150
|
-
end
|
151
|
-
|
152
|
-
# @api public
|
153
|
-
def transaction_id=(id)
|
154
|
-
paper_trail_store[:transaction_id] = id
|
155
|
-
end
|
156
|
-
|
157
|
-
# Thread-safe hash to hold PaperTrail's data. Initializing with needed
|
158
|
-
# default values.
|
159
|
-
# @api private
|
160
|
-
def paper_trail_store
|
161
|
-
RequestStore.store[:paper_trail] ||= { request_enabled_for_controller: true }
|
162
|
-
end
|
163
|
-
|
164
|
-
# Returns PaperTrail's configuration object.
|
113
|
+
# Returns PaperTrail's global configuration object, a singleton. These
|
114
|
+
# settings affect all threads.
|
165
115
|
# @api private
|
166
116
|
def config
|
167
117
|
@config ||= PaperTrail::Config.instance
|
@@ -176,25 +126,27 @@ module PaperTrail
|
|
176
126
|
end
|
177
127
|
end
|
178
128
|
|
179
|
-
#
|
180
|
-
#
|
181
|
-
|
182
|
-
|
183
|
-
begin
|
184
|
-
require "protected_attributes"
|
185
|
-
rescue LoadError # rubocop:disable Lint/HandleExceptions
|
186
|
-
# In case `protected_attributes` gem is not available.
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
129
|
+
# We use the `on_load` "hook" instead of `ActiveRecord::Base.include` because we
|
130
|
+
# don't want to cause all of AR to be autloaded yet. See
|
131
|
+
# https://guides.rubyonrails.org/engines.html#what-are-on-load-hooks-questionmark
|
132
|
+
# to learn more about `on_load`.
|
190
133
|
ActiveSupport.on_load(:active_record) do
|
191
134
|
include PaperTrail::Model
|
192
135
|
end
|
193
136
|
|
194
137
|
# Require frameworks
|
195
|
-
|
196
|
-
|
197
|
-
|
138
|
+
if defined?(::Rails)
|
139
|
+
# Rails module is sometimes defined by gems like rails-html-sanitizer
|
140
|
+
# so we check for presence of Rails.application.
|
141
|
+
if defined?(::Rails.application)
|
142
|
+
require "paper_trail/frameworks/rails"
|
143
|
+
else
|
144
|
+
::Kernel.warn(::PaperTrail::E_RAILS_NOT_LOADED)
|
145
|
+
end
|
198
146
|
else
|
199
147
|
require "paper_trail/frameworks/active_record"
|
200
148
|
end
|
149
|
+
|
150
|
+
if defined?(::ActiveRecord)
|
151
|
+
::PaperTrail::Compatibility.check_activerecord(::ActiveRecord.gem_version)
|
152
|
+
end
|