paper_trail 4.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CONTRIBUTING.md +105 -0
  3. data/.github/ISSUE_TEMPLATE.md +13 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +100 -0
  6. data/.rubocop_todo.yml +14 -0
  7. data/.travis.yml +11 -10
  8. data/Appraisals +37 -0
  9. data/CHANGELOG.md +173 -8
  10. data/Gemfile +1 -1
  11. data/README.md +641 -470
  12. data/Rakefile +19 -19
  13. data/doc/bug_report_template.rb +71 -0
  14. data/doc/warning_about_not_setting_whodunnit.md +32 -0
  15. data/gemfiles/ar3.gemfile +18 -0
  16. data/gemfiles/ar4.gemfile +7 -0
  17. data/gemfiles/ar5.gemfile +13 -0
  18. data/lib/generators/paper_trail/install_generator.rb +26 -18
  19. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +3 -1
  20. data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +2 -0
  21. data/lib/generators/paper_trail/templates/create_version_associations.rb +9 -4
  22. data/lib/generators/paper_trail/templates/create_versions.rb +53 -5
  23. data/lib/paper_trail/attribute_serializers/README.md +10 -0
  24. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +58 -0
  25. data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +48 -0
  26. data/lib/paper_trail/attribute_serializers/object_attribute.rb +39 -0
  27. data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +42 -0
  28. data/lib/paper_trail/cleaner.rb +41 -18
  29. data/lib/paper_trail/config.rb +42 -26
  30. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +5 -1
  31. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +6 -2
  32. data/lib/paper_trail/frameworks/active_record.rb +2 -2
  33. data/lib/paper_trail/frameworks/cucumber.rb +1 -0
  34. data/lib/paper_trail/frameworks/rails/controller.rb +50 -14
  35. data/lib/paper_trail/frameworks/rails/engine.rb +6 -1
  36. data/lib/paper_trail/frameworks/rails.rb +2 -7
  37. data/lib/paper_trail/frameworks/rspec/helpers.rb +3 -1
  38. data/lib/paper_trail/frameworks/rspec.rb +5 -5
  39. data/lib/paper_trail/frameworks/sinatra.rb +8 -5
  40. data/lib/paper_trail/has_paper_trail.rb +381 -221
  41. data/lib/paper_trail/record_history.rb +57 -0
  42. data/lib/paper_trail/reifier.rb +450 -0
  43. data/lib/paper_trail/serializers/json.rb +7 -7
  44. data/lib/paper_trail/serializers/yaml.rb +31 -12
  45. data/lib/paper_trail/version_association_concern.rb +6 -2
  46. data/lib/paper_trail/version_concern.rb +200 -287
  47. data/lib/paper_trail/version_number.rb +6 -9
  48. data/lib/paper_trail.rb +169 -137
  49. data/paper_trail.gemspec +41 -43
  50. data/spec/generators/install_generator_spec.rb +24 -25
  51. data/spec/generators/paper_trail/templates/create_versions_spec.rb +51 -0
  52. data/spec/models/animal_spec.rb +23 -6
  53. data/spec/models/boolit_spec.rb +8 -8
  54. data/spec/models/callback_modifier_spec.rb +96 -0
  55. data/spec/models/car_spec.rb +13 -0
  56. data/spec/models/fluxor_spec.rb +3 -3
  57. data/spec/models/gadget_spec.rb +19 -19
  58. data/spec/models/joined_version_spec.rb +3 -3
  59. data/spec/models/json_version_spec.rb +50 -28
  60. data/spec/models/kitchen/banana_spec.rb +3 -3
  61. data/spec/models/not_on_update_spec.rb +7 -4
  62. data/spec/models/post_with_status_spec.rb +13 -3
  63. data/spec/models/skipper_spec.rb +40 -11
  64. data/spec/models/thing_spec.rb +4 -4
  65. data/spec/models/truck_spec.rb +5 -0
  66. data/spec/models/vehicle_spec.rb +5 -0
  67. data/spec/models/version_spec.rb +103 -59
  68. data/spec/models/widget_spec.rb +86 -55
  69. data/spec/modules/paper_trail_spec.rb +2 -2
  70. data/spec/modules/version_concern_spec.rb +11 -12
  71. data/spec/modules/version_number_spec.rb +3 -4
  72. data/spec/paper_trail/config_spec.rb +33 -0
  73. data/spec/paper_trail_spec.rb +16 -14
  74. data/spec/rails_helper.rb +10 -9
  75. data/spec/requests/articles_spec.rb +11 -7
  76. data/spec/spec_helper.rb +42 -17
  77. data/spec/support/alt_db_init.rb +8 -13
  78. data/test/custom_json_serializer.rb +3 -3
  79. data/test/dummy/Rakefile +2 -2
  80. data/test/dummy/app/controllers/application_controller.rb +21 -8
  81. data/test/dummy/app/controllers/articles_controller.rb +11 -8
  82. data/test/dummy/app/controllers/widgets_controller.rb +13 -12
  83. data/test/dummy/app/models/animal.rb +1 -1
  84. data/test/dummy/app/models/article.rb +19 -11
  85. data/test/dummy/app/models/authorship.rb +1 -1
  86. data/test/dummy/app/models/bar_habtm.rb +4 -0
  87. data/test/dummy/app/models/book.rb +4 -4
  88. data/test/dummy/app/models/boolit.rb +1 -1
  89. data/test/dummy/app/models/callback_modifier.rb +45 -0
  90. data/test/dummy/app/models/car.rb +3 -0
  91. data/test/dummy/app/models/chapter.rb +9 -0
  92. data/test/dummy/app/models/citation.rb +5 -0
  93. data/test/dummy/app/models/customer.rb +1 -1
  94. data/test/dummy/app/models/document.rb +2 -2
  95. data/test/dummy/app/models/editor.rb +1 -1
  96. data/test/dummy/app/models/foo_habtm.rb +5 -0
  97. data/test/dummy/app/models/fruit.rb +2 -2
  98. data/test/dummy/app/models/gadget.rb +1 -1
  99. data/test/dummy/app/models/kitchen/banana.rb +1 -1
  100. data/test/dummy/app/models/legacy_widget.rb +2 -2
  101. data/test/dummy/app/models/line_item.rb +1 -1
  102. data/test/dummy/app/models/not_on_update.rb +1 -1
  103. data/test/dummy/app/models/paragraph.rb +5 -0
  104. data/test/dummy/app/models/person.rb +6 -6
  105. data/test/dummy/app/models/post.rb +1 -1
  106. data/test/dummy/app/models/post_with_status.rb +1 -1
  107. data/test/dummy/app/models/quotation.rb +5 -0
  108. data/test/dummy/app/models/section.rb +6 -0
  109. data/test/dummy/app/models/skipper.rb +2 -2
  110. data/test/dummy/app/models/song.rb +13 -4
  111. data/test/dummy/app/models/thing.rb +2 -2
  112. data/test/dummy/app/models/translation.rb +2 -2
  113. data/test/dummy/app/models/truck.rb +4 -0
  114. data/test/dummy/app/models/vehicle.rb +4 -0
  115. data/test/dummy/app/models/whatchamajigger.rb +1 -1
  116. data/test/dummy/app/models/widget.rb +7 -6
  117. data/test/dummy/app/versions/joined_version.rb +4 -3
  118. data/test/dummy/app/versions/json_version.rb +1 -1
  119. data/test/dummy/app/versions/kitchen/banana_version.rb +1 -1
  120. data/test/dummy/app/versions/post_version.rb +2 -2
  121. data/test/dummy/config/application.rb +20 -9
  122. data/test/dummy/config/boot.rb +5 -5
  123. data/test/dummy/config/database.postgres.yml +1 -1
  124. data/test/dummy/config/environment.rb +1 -1
  125. data/test/dummy/config/environments/development.rb +4 -3
  126. data/test/dummy/config/environments/production.rb +3 -2
  127. data/test/dummy/config/environments/test.rb +15 -5
  128. data/test/dummy/config/initializers/backtrace_silencers.rb +4 -2
  129. data/test/dummy/config/initializers/paper_trail.rb +4 -3
  130. data/test/dummy/config/initializers/secret_token.rb +3 -1
  131. data/test/dummy/config/initializers/session_store.rb +1 -1
  132. data/test/dummy/config/routes.rb +2 -2
  133. data/test/dummy/config.ru +1 -1
  134. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +148 -68
  135. data/test/dummy/db/schema.rb +119 -31
  136. data/test/dummy/script/rails +6 -4
  137. data/test/functional/controller_test.rb +34 -35
  138. data/test/functional/enabled_for_controller_test.rb +6 -7
  139. data/test/functional/modular_sinatra_test.rb +43 -38
  140. data/test/functional/sinatra_test.rb +49 -40
  141. data/test/functional/thread_safety_test.rb +4 -6
  142. data/test/paper_trail_test.rb +15 -14
  143. data/test/test_helper.rb +78 -18
  144. data/test/time_travel_helper.rb +1 -15
  145. data/test/unit/associations_test.rb +1016 -0
  146. data/test/unit/cleaner_test.rb +66 -60
  147. data/test/unit/inheritance_column_test.rb +19 -19
  148. data/test/unit/model_test.rb +646 -1071
  149. data/test/unit/protected_attrs_test.rb +19 -14
  150. data/test/unit/serializer_test.rb +44 -43
  151. data/test/unit/serializers/json_test.rb +28 -21
  152. data/test/unit/serializers/mixin_json_test.rb +15 -14
  153. data/test/unit/serializers/mixin_yaml_test.rb +20 -16
  154. data/test/unit/serializers/yaml_test.rb +16 -14
  155. data/test/unit/timestamp_test.rb +10 -12
  156. data/test/unit/version_test.rb +88 -70
  157. metadata +166 -72
  158. data/gemfiles/3.0.gemfile +0 -52
@@ -1,48 +1,64 @@
1
- require 'singleton'
2
- require 'paper_trail/serializers/yaml'
1
+ require "singleton"
2
+ require "paper_trail/serializers/yaml"
3
3
 
4
4
  module PaperTrail
5
+ # Global configuration affecting all threads. Some thread-specific
6
+ # configuration can be found in `paper_trail.rb`, others in `controller.rb`.
5
7
  class Config
6
8
  include Singleton
7
9
  attr_accessor :timestamp_field, :serializer, :version_limit
8
- attr_reader :serialized_attributes
9
10
  attr_writer :track_associations
10
11
 
11
12
  def initialize
13
+ # Variables which affect all threads, whose access is synchronized.
14
+ @mutex = Mutex.new
15
+ @enabled = true
16
+
17
+ # Variables which affect all threads, whose access is *not* synchronized.
12
18
  @timestamp_field = :created_at
13
- @serializer = PaperTrail::Serializers::YAML
19
+ @serializer = PaperTrail::Serializers::YAML
20
+ end
14
21
 
15
- # This setting only defaults to false on AR 4.2+, because that's when
16
- # it was deprecated. We want it to function with older versions of
17
- # ActiveRecord by default.
18
- if ::ActiveRecord::VERSION::STRING < '4.2'
19
- @serialized_attributes = true
20
- end
22
+ def serialized_attributes
23
+ ActiveSupport::Deprecation.warn(
24
+ "PaperTrail.config.serialized_attributes is deprecated without " +
25
+ "replacement and always returns false."
26
+ )
27
+ false
21
28
  end
22
29
 
23
- def serialized_attributes=(value)
24
- if ::ActiveRecord::VERSION::MAJOR >= 5
25
- ::ActiveSupport::Deprecation.warn(
26
- "ActiveRecord 5.0 deprecated `serialized_attributes` " +
27
- "without replacement, so this PaperTrail config setting does " +
28
- "nothing with this version, and is always turned off"
29
- )
30
- end
31
- @serialized_attributes = value
30
+ def serialized_attributes=(_)
31
+ ActiveSupport::Deprecation.warn(
32
+ "PaperTrail.config.serialized_attributes= is deprecated without " +
33
+ "replacement and no longer has any effect."
34
+ )
32
35
  end
33
36
 
34
- def track_associations
35
- @track_associations ||= PaperTrail::VersionAssociation.table_exists?
37
+ # Previously, we checked `PaperTrail::VersionAssociation.table_exists?`
38
+ # here, but that proved to be problematic in situations when the database
39
+ # connection had not been established, or when the database does not exist
40
+ # yet (as with `rake db:create`).
41
+ def track_associations?
42
+ if @track_associations.nil?
43
+ ActiveSupport::Deprecation.warn <<-EOS.strip_heredoc.gsub(/\s+/, " ")
44
+ PaperTrail.track_associations has not been set. As of PaperTrail 5, it
45
+ defaults to false. Tracking associations is an experimental feature so
46
+ we recommend setting PaperTrail.config.track_associations = false in
47
+ your config/initializers/paper_trail.rb
48
+ EOS
49
+ false
50
+ else
51
+ @track_associations
52
+ end
36
53
  end
37
- alias_method :track_associations?, :track_associations
38
54
 
39
- # Indicates whether PaperTrail is on or off.
55
+ # Indicates whether PaperTrail is on or off. Default: true.
40
56
  def enabled
41
- PaperTrail.paper_trail_store[:paper_trail_enabled].nil? || PaperTrail.paper_trail_store[:paper_trail_enabled]
57
+ @mutex.synchronize { !!@enabled }
42
58
  end
43
59
 
44
- def enabled= enable
45
- PaperTrail.paper_trail_store[:paper_trail_enabled] = enable
60
+ def enabled=(enable)
61
+ @mutex.synchronize { @enabled = enable }
46
62
  end
47
63
  end
48
64
  end
@@ -1,6 +1,10 @@
1
- require 'paper_trail/version_concern'
1
+ require "paper_trail/version_concern"
2
2
 
3
3
  module PaperTrail
4
+ # This is the default ActiveRecord model provided by PaperTrail. Most simple
5
+ # applications will only use this and its partner, `VersionAssociation`, but
6
+ # it is possible to sub-class, extend, or even do without this model entirely.
7
+ # See the readme for details.
4
8
  class Version < ::ActiveRecord::Base
5
9
  include PaperTrail::VersionConcern
6
10
  end
@@ -1,7 +1,11 @@
1
- require 'paper_trail/version_association_concern'
1
+ require "paper_trail/version_association_concern"
2
2
 
3
3
  module PaperTrail
4
+ # This is the default ActiveRecord model provided by PaperTrail. Most simple
5
+ # applications will only use this and its partner, `Version`, but it is
6
+ # possible to sub-class, extend, or even do without this model entirely.
7
+ # See the readme for details.
4
8
  class VersionAssociation < ::ActiveRecord::Base
5
9
  include PaperTrail::VersionAssociationConcern
6
10
  end
7
- end
11
+ end
@@ -1,4 +1,4 @@
1
- # This file only needs to be loaded if the gem is being used outside of Rails, since otherwise
2
- # the model(s) will get loaded in via the `Rails::Engine`
1
+ # This file only needs to be loaded if the gem is being used outside of Rails,
2
+ # since otherwise the model(s) will get loaded in via the `Rails::Engine`.
3
3
  require "paper_trail/frameworks/active_record/models/paper_trail/version_association"
4
4
  require "paper_trail/frameworks/active_record/models/paper_trail/version"
@@ -8,6 +8,7 @@ end
8
8
 
9
9
  module PaperTrail
10
10
  module Cucumber
11
+ # Helper method for enabling PT in Cucumber features.
11
12
  module Extensions
12
13
  # :call-seq:
13
14
  # with_versioning
@@ -1,10 +1,27 @@
1
1
  module PaperTrail
2
2
  module Rails
3
+ # Extensions to rails controllers. Provides convenient ways to pass certain
4
+ # information to the model layer, with `controller_info` and `whodunnit`.
5
+ # Also includes a convenient on/off switch, `enabled_for_controller`.
3
6
  module Controller
4
-
5
7
  def self.included(base)
6
- base.before_filter :set_paper_trail_enabled_for_controller
7
- base.before_filter :set_paper_trail_whodunnit, :set_paper_trail_controller_info
8
+ before = [
9
+ :set_paper_trail_enabled_for_controller,
10
+ :set_paper_trail_controller_info
11
+ ]
12
+ after = [
13
+ :warn_about_not_setting_whodunnit
14
+ ]
15
+
16
+ if base.respond_to? :before_action
17
+ # Rails 4+
18
+ before.map { |sym| base.before_action sym }
19
+ after.map { |sym| base.after_action sym }
20
+ else
21
+ # Rails 3.
22
+ before.map { |sym| base.before_filter sym }
23
+ after.map { |sym| base.after_filter sym }
24
+ end
8
25
  end
9
26
 
10
27
  protected
@@ -36,43 +53,62 @@ module PaperTrail
36
53
  #
37
54
  # The columns `ip` and `user_agent` must exist in your `versions` # table.
38
55
  #
39
- # Use the `:meta` option to `PaperTrail::Model::ClassMethods.has_paper_trail`
40
- # to store any extra model-level data you need.
56
+ # Use the `:meta` option to
57
+ # `PaperTrail::Model::ClassMethods.has_paper_trail` to store any extra
58
+ # model-level data you need.
41
59
  def info_for_paper_trail
42
60
  {}
43
61
  end
44
62
 
45
- # Returns `true` (default) or `false` depending on whether PaperTrail should
46
- # be active for the current request.
63
+ # Returns `true` (default) or `false` depending on whether PaperTrail
64
+ # should be active for the current request.
47
65
  #
48
- # Override this method in your controller to specify when PaperTrail should
49
- # be off.
66
+ # Override this method in your controller to specify when PaperTrail
67
+ # should be off.
50
68
  def paper_trail_enabled_for_controller
51
69
  ::PaperTrail.enabled?
52
70
  end
53
71
 
54
72
  private
55
73
 
56
- # Tells PaperTrail whether versions should be saved in the current request.
74
+ # Tells PaperTrail whether versions should be saved in the current
75
+ # request.
57
76
  def set_paper_trail_enabled_for_controller
58
77
  ::PaperTrail.enabled_for_controller = paper_trail_enabled_for_controller
59
78
  end
60
79
 
61
80
  # Tells PaperTrail who is responsible for any changes that occur.
62
81
  def set_paper_trail_whodunnit
82
+ @set_paper_trail_whodunnit_called = true
63
83
  ::PaperTrail.whodunnit = user_for_paper_trail if ::PaperTrail.enabled_for_controller?
64
84
  end
65
85
 
66
- # Tells PaperTrail any information from the controller you want
67
- # to store alongside any changes that occur.
86
+ # Tells PaperTrail any information from the controller you want to store
87
+ # alongside any changes that occur.
68
88
  def set_paper_trail_controller_info
69
89
  ::PaperTrail.controller_info = info_for_paper_trail if ::PaperTrail.enabled_for_controller?
70
90
  end
71
91
 
92
+ def warn_about_not_setting_whodunnit
93
+ enabled = ::PaperTrail.enabled_for_controller?
94
+ user_present = user_for_paper_trail.present?
95
+ whodunnit_blank = ::PaperTrail.whodunnit.blank?
96
+ if enabled && user_present && whodunnit_blank && !@set_paper_trail_whodunnit_called
97
+ ::Kernel.warn <<-EOS.strip_heredoc
98
+ user_for_paper_trail is present, but whodunnit has not been set.
99
+ PaperTrail no longer adds the set_paper_trail_whodunnit callback for
100
+ you. To continue recording whodunnit, please add this before_action
101
+ callback to your ApplicationController . For more information,
102
+ please see https://git.io/vrTsk
103
+ EOS
104
+ end
105
+ end
72
106
  end
73
107
  end
108
+ end
74
109
 
75
- if defined?(::ActionController)
76
- ::ActiveSupport.on_load(:action_controller) { include PaperTrail::Rails::Controller }
110
+ if defined?(::ActionController)
111
+ ::ActiveSupport.on_load(:action_controller) do
112
+ include ::PaperTrail::Rails::Controller
77
113
  end
78
114
  end
@@ -1,7 +1,12 @@
1
1
  module PaperTrail
2
2
  module Rails
3
+ # See http://guides.rubyonrails.org/engines.html
3
4
  class Engine < ::Rails::Engine
4
- paths['app/models'] << 'lib/paper_trail/frameworks/active_record/models'
5
+ paths["app/models"] << "lib/paper_trail/frameworks/active_record/models"
6
+ config.paper_trail = ActiveSupport::OrderedOptions.new
7
+ initializer "paper_trail.initialisation" do |app|
8
+ PaperTrail.enabled = app.config.paper_trail.fetch(:enabled, true)
9
+ end
5
10
  end
6
11
  end
7
12
  end
@@ -1,7 +1,2 @@
1
- require 'paper_trail/frameworks/rails/controller'
2
- require 'paper_trail/frameworks/rails/engine'
3
-
4
- module PaperTrail
5
- module Rails
6
- end
7
- end
1
+ require "paper_trail/frameworks/rails/controller"
2
+ require "paper_trail/frameworks/rails/engine"
@@ -1,6 +1,7 @@
1
1
  module PaperTrail
2
2
  module RSpec
3
3
  module Helpers
4
+ # Included in the RSpec configuration in `frameworks/rspec.rb`
4
5
  module InstanceMethods
5
6
  # enable versioning for specific blocks (at instance-level)
6
7
  def with_versioning
@@ -12,10 +13,11 @@ module PaperTrail
12
13
  end
13
14
  end
14
15
 
16
+ # Extended by the RSpec configuration in `frameworks/rspec.rb`
15
17
  module ClassMethods
16
18
  # enable versioning for specific blocks (at class-level)
17
19
  def with_versioning(&block)
18
- context 'with versioning', :versioning => true do
20
+ context "with versioning", versioning: true do
19
21
  class_exec(&block)
20
22
  end
21
23
  end
@@ -1,6 +1,6 @@
1
- require 'rspec/core'
2
- require 'rspec/matchers'
3
- require 'paper_trail/frameworks/rspec/helpers'
1
+ require "rspec/core"
2
+ require "rspec/matchers"
3
+ require "paper_trail/frameworks/rspec/helpers"
4
4
 
5
5
  RSpec.configure do |config|
6
6
  config.include ::PaperTrail::RSpec::Helpers::InstanceMethods
@@ -13,14 +13,14 @@ RSpec.configure do |config|
13
13
  ::PaperTrail.controller_info = {} if defined?(::Rails) && defined?(::RSpec::Rails)
14
14
  end
15
15
 
16
- config.before(:each, :versioning => true) do
16
+ config.before(:each, versioning: true) do
17
17
  ::PaperTrail.enabled = true
18
18
  end
19
19
  end
20
20
 
21
21
  RSpec::Matchers.define :be_versioned do
22
22
  # check to see if the model has `has_paper_trail` declared on it
23
- match { |actual| actual.kind_of?(::PaperTrail::Model::InstanceMethods) }
23
+ match { |actual| actual.is_a?(::PaperTrail::Model::InstanceMethods) }
24
24
  end
25
25
 
26
26
  RSpec::Matchers.define :have_a_version_with do |attributes|
@@ -1,9 +1,10 @@
1
- require 'active_support/core_ext/object' # provides the `try` method
1
+ require "active_support/core_ext/object" # provides the `try` method
2
2
 
3
3
  module PaperTrail
4
+ # Extensions to `Sinatra`.
4
5
  module Sinatra
5
-
6
- # Register this module inside your Sinatra application to gain access to controller-level methods used by PaperTrail
6
+ # Register this module inside your Sinatra application to gain access to
7
+ # controller-level methods used by PaperTrail.
7
8
  def self.registered(app)
8
9
  app.use RequestStore::Middleware
9
10
  app.helpers self
@@ -28,10 +29,12 @@ module PaperTrail
28
29
 
29
30
  # Tells PaperTrail who is responsible for any changes that occur.
30
31
  def set_paper_trail_whodunnit
32
+ @set_paper_trail_whodunnit_called = true
31
33
  ::PaperTrail.whodunnit = user_for_paper_trail if ::PaperTrail.enabled?
32
34
  end
33
-
34
35
  end
36
+ end
35
37
 
36
- ::Sinatra.register PaperTrail::Sinatra if defined?(::Sinatra)
38
+ if defined?(::Sinatra)
39
+ ::Sinatra.register(::PaperTrail::Sinatra)
37
40
  end