paper_trail 4.2.0 → 5.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 +4 -4
- data/{CONTRIBUTING.md → .github/CONTRIBUTING.md} +28 -9
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +100 -0
- data/.rubocop_todo.yml +14 -0
- data/.travis.yml +8 -9
- data/Appraisals +41 -0
- data/CHANGELOG.md +49 -9
- data/Gemfile +1 -1
- data/README.md +130 -109
- data/Rakefile +19 -19
- data/doc/bug_report_template.rb +20 -14
- data/gemfiles/ar3.gemfile +10 -53
- data/gemfiles/ar4.gemfile +7 -0
- data/gemfiles/ar5.gemfile +13 -0
- data/lib/generators/paper_trail/install_generator.rb +26 -18
- data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +4 -2
- data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +2 -0
- data/lib/generators/paper_trail/templates/create_version_associations.rb +9 -4
- data/lib/generators/paper_trail/templates/create_versions.rb +39 -5
- data/lib/paper_trail.rb +169 -146
- data/lib/paper_trail/attributes_serialization.rb +89 -17
- data/lib/paper_trail/cleaner.rb +15 -9
- data/lib/paper_trail/config.rb +28 -11
- data/lib/paper_trail/frameworks/active_record.rb +4 -0
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +5 -1
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +6 -2
- data/lib/paper_trail/frameworks/cucumber.rb +1 -0
- data/lib/paper_trail/frameworks/rails.rb +2 -7
- data/lib/paper_trail/frameworks/rails/controller.rb +29 -9
- data/lib/paper_trail/frameworks/rails/engine.rb +7 -1
- data/lib/paper_trail/frameworks/rspec.rb +5 -5
- data/lib/paper_trail/frameworks/rspec/helpers.rb +3 -1
- data/lib/paper_trail/frameworks/sinatra.rb +6 -4
- data/lib/paper_trail/has_paper_trail.rb +199 -106
- data/lib/paper_trail/record_history.rb +1 -3
- data/lib/paper_trail/reifier.rb +297 -118
- data/lib/paper_trail/serializers/json.rb +3 -3
- data/lib/paper_trail/serializers/yaml.rb +27 -8
- data/lib/paper_trail/version_association_concern.rb +3 -1
- data/lib/paper_trail/version_concern.rb +75 -35
- data/lib/paper_trail/version_number.rb +6 -9
- data/paper_trail.gemspec +44 -51
- data/spec/generators/install_generator_spec.rb +24 -25
- data/spec/generators/paper_trail/templates/create_versions_spec.rb +51 -0
- data/spec/models/animal_spec.rb +12 -12
- data/spec/models/boolit_spec.rb +8 -8
- data/spec/models/callback_modifier_spec.rb +47 -47
- data/spec/models/car_spec.rb +13 -0
- data/spec/models/fluxor_spec.rb +3 -3
- data/spec/models/gadget_spec.rb +19 -19
- data/spec/models/joined_version_spec.rb +3 -3
- data/spec/models/json_version_spec.rb +23 -24
- data/spec/models/kitchen/banana_spec.rb +3 -3
- data/spec/models/not_on_update_spec.rb +7 -4
- data/spec/models/post_with_status_spec.rb +13 -3
- data/spec/models/skipper_spec.rb +10 -10
- data/spec/models/thing_spec.rb +4 -4
- data/spec/models/truck_spec.rb +5 -0
- data/spec/models/vehicle_spec.rb +5 -0
- data/spec/models/version_spec.rb +103 -59
- data/spec/models/widget_spec.rb +82 -52
- data/spec/modules/paper_trail_spec.rb +2 -2
- data/spec/modules/version_concern_spec.rb +11 -12
- data/spec/modules/version_number_spec.rb +2 -4
- data/spec/paper_trail/config_spec.rb +10 -29
- data/spec/paper_trail_spec.rb +16 -14
- data/spec/rails_helper.rb +10 -9
- data/spec/requests/articles_spec.rb +11 -7
- data/spec/spec_helper.rb +41 -22
- data/spec/support/alt_db_init.rb +8 -13
- data/test/custom_json_serializer.rb +3 -3
- data/test/dummy/Rakefile +2 -2
- data/test/dummy/app/controllers/application_controller.rb +21 -8
- data/test/dummy/app/controllers/articles_controller.rb +11 -8
- data/test/dummy/app/controllers/widgets_controller.rb +13 -12
- data/test/dummy/app/models/animal.rb +1 -1
- data/test/dummy/app/models/article.rb +19 -11
- data/test/dummy/app/models/authorship.rb +1 -1
- data/test/dummy/app/models/bar_habtm.rb +4 -0
- data/test/dummy/app/models/book.rb +4 -4
- data/test/dummy/app/models/boolit.rb +1 -1
- data/test/dummy/app/models/callback_modifier.rb +6 -6
- data/test/dummy/app/models/car.rb +3 -0
- data/test/dummy/app/models/chapter.rb +4 -4
- data/test/dummy/app/models/customer.rb +1 -1
- data/test/dummy/app/models/document.rb +2 -2
- data/test/dummy/app/models/editor.rb +1 -1
- data/test/dummy/app/models/foo_habtm.rb +4 -0
- data/test/dummy/app/models/fruit.rb +2 -2
- data/test/dummy/app/models/gadget.rb +1 -1
- data/test/dummy/app/models/kitchen/banana.rb +1 -1
- data/test/dummy/app/models/legacy_widget.rb +2 -2
- data/test/dummy/app/models/line_item.rb +1 -1
- data/test/dummy/app/models/not_on_update.rb +1 -1
- data/test/dummy/app/models/person.rb +6 -6
- data/test/dummy/app/models/post.rb +1 -1
- data/test/dummy/app/models/post_with_status.rb +1 -1
- data/test/dummy/app/models/quotation.rb +1 -1
- data/test/dummy/app/models/section.rb +1 -1
- data/test/dummy/app/models/skipper.rb +2 -2
- data/test/dummy/app/models/song.rb +13 -4
- data/test/dummy/app/models/thing.rb +2 -2
- data/test/dummy/app/models/translation.rb +2 -2
- data/test/dummy/app/models/truck.rb +4 -0
- data/test/dummy/app/models/vehicle.rb +4 -0
- data/test/dummy/app/models/whatchamajigger.rb +1 -1
- data/test/dummy/app/models/widget.rb +7 -6
- data/test/dummy/app/versions/joined_version.rb +4 -3
- data/test/dummy/app/versions/json_version.rb +1 -1
- data/test/dummy/app/versions/kitchen/banana_version.rb +1 -1
- data/test/dummy/app/versions/post_version.rb +2 -2
- data/test/dummy/config.ru +1 -1
- data/test/dummy/config/application.rb +20 -9
- data/test/dummy/config/boot.rb +5 -5
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +4 -3
- data/test/dummy/config/environments/production.rb +3 -2
- data/test/dummy/config/environments/test.rb +15 -5
- data/test/dummy/config/initializers/backtrace_silencers.rb +4 -2
- data/test/dummy/config/initializers/paper_trail.rb +1 -2
- data/test/dummy/config/initializers/secret_token.rb +3 -1
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/routes.rb +2 -2
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +120 -74
- data/test/dummy/db/schema.rb +29 -6
- data/test/dummy/script/rails +6 -4
- data/test/functional/controller_test.rb +34 -35
- data/test/functional/enabled_for_controller_test.rb +6 -7
- data/test/functional/modular_sinatra_test.rb +43 -38
- data/test/functional/sinatra_test.rb +49 -40
- data/test/functional/thread_safety_test.rb +4 -6
- data/test/paper_trail_test.rb +15 -14
- data/test/test_helper.rb +68 -44
- data/test/time_travel_helper.rb +1 -15
- data/test/unit/associations_test.rb +517 -251
- data/test/unit/cleaner_test.rb +66 -60
- data/test/unit/inheritance_column_test.rb +17 -17
- data/test/unit/model_test.rb +611 -504
- data/test/unit/protected_attrs_test.rb +16 -12
- data/test/unit/serializer_test.rb +44 -43
- data/test/unit/serializers/json_test.rb +17 -18
- data/test/unit/serializers/mixin_json_test.rb +15 -14
- data/test/unit/serializers/mixin_yaml_test.rb +20 -16
- data/test/unit/serializers/yaml_test.rb +12 -13
- data/test/unit/timestamp_test.rb +10 -12
- data/test/unit/version_test.rb +7 -7
- metadata +92 -40
@@ -1,5 +1,14 @@
|
|
1
1
|
module PaperTrail
|
2
|
+
# "Serialization" here refers to the preparation of data for insertion into a
|
3
|
+
# database, particularly the `object` and `object_changes` columns in the
|
4
|
+
# `versions` table.
|
5
|
+
#
|
6
|
+
# Likewise, "deserialization" refers to any processing of data after they
|
7
|
+
# have been read from the database, for example preparing the result of
|
8
|
+
# `VersionConcern#changeset`.
|
2
9
|
module AttributesSerialization
|
10
|
+
# An attribute which needs no processing. It is part of our backport (shim)
|
11
|
+
# of rails 4.2's attribute API. See `type_for_attribute` below.
|
3
12
|
class NoOpAttribute
|
4
13
|
def type_cast_for_database(value)
|
5
14
|
value
|
@@ -11,6 +20,9 @@ module PaperTrail
|
|
11
20
|
end
|
12
21
|
NO_OP_ATTRIBUTE = NoOpAttribute.new
|
13
22
|
|
23
|
+
# An attribute which requires manual (de)serialization to/from what we get
|
24
|
+
# from the database. It is part of our backport (shim) of rails 4.2's
|
25
|
+
# attribute API. See `type_for_attribute` below.
|
14
26
|
class SerializedAttribute
|
15
27
|
def initialize(coder)
|
16
28
|
@coder = coder.respond_to?(:dump) ? coder : PaperTrail.serializer
|
@@ -25,16 +37,72 @@ module PaperTrail
|
|
25
37
|
end
|
26
38
|
end
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
# The `AbstractSerializer` (de)serializes model attribute values. For
|
41
|
+
# example, the string "1.99" serializes into the integer `1` when assigned
|
42
|
+
# to an attribute of type `ActiveRecord::Type::Integer`.
|
43
|
+
#
|
44
|
+
# This implementation depends on the `type_for_attribute` method, which was
|
45
|
+
# introduced in rails 4.2. In older versions of rails, we shim this method
|
46
|
+
# below.
|
47
|
+
#
|
48
|
+
# At runtime, the `AbstractSerializer` has only one child class, the
|
49
|
+
# `CastedAttributeSerializer`, whose implementation varies depending on the
|
50
|
+
# version of ActiveRecord.
|
51
|
+
class AbstractSerializer
|
52
|
+
def initialize(klass)
|
53
|
+
@klass = klass
|
33
54
|
end
|
34
55
|
|
35
|
-
|
36
|
-
|
37
|
-
|
56
|
+
private
|
57
|
+
|
58
|
+
def apply_serialization(method, attr, val)
|
59
|
+
@klass.type_for_attribute(attr).send(method, val)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if ::ActiveRecord::VERSION::MAJOR >= 5
|
64
|
+
# This implementation uses AR 5's `serialize` and `deserialize`.
|
65
|
+
class CastedAttributeSerializer < AbstractSerializer
|
66
|
+
def serialize(attr, val)
|
67
|
+
apply_serialization(:serialize, attr, val)
|
68
|
+
end
|
69
|
+
|
70
|
+
def deserialize(attr, val)
|
71
|
+
apply_serialization(:deserialize, attr, val)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
# This implementation uses AR 4.2's `type_cast_for_database`. For
|
76
|
+
# versions of AR < 4.2 we provide an implementation of
|
77
|
+
# `type_cast_for_database` in our shim attribute type classes,
|
78
|
+
# `NoOpAttribute` and `SerializedAttribute`.
|
79
|
+
class CastedAttributeSerializer < AbstractSerializer
|
80
|
+
def serialize(attr, val)
|
81
|
+
val = defined_enums[attr][val] if defined_enums[attr]
|
82
|
+
apply_serialization(:type_cast_for_database, attr, val)
|
83
|
+
end
|
84
|
+
|
85
|
+
def deserialize(attr, val)
|
86
|
+
val = apply_serialization(:type_cast_from_database, attr, val)
|
87
|
+
|
88
|
+
if defined_enums[attr]
|
89
|
+
defined_enums[attr].key(val)
|
90
|
+
else
|
91
|
+
val
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def defined_enums
|
98
|
+
@defined_enums ||= (@klass.respond_to?(:defined_enums) ? @klass.defined_enums : {})
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Backport Rails 4.2 and later's `type_for_attribute` so we can build
|
104
|
+
# on a common interface.
|
105
|
+
if ::ActiveRecord::VERSION::STRING < "4.2"
|
38
106
|
def type_for_attribute(attr_name)
|
39
107
|
serialized_attribute_types[attr_name.to_s] || NO_OP_ATTRIBUTE
|
40
108
|
end
|
@@ -49,40 +117,44 @@ module PaperTrail
|
|
49
117
|
|
50
118
|
# Used for `Version#object` attribute.
|
51
119
|
def serialize_attributes_for_paper_trail!(attributes)
|
52
|
-
alter_attributes_for_paper_trail!(
|
120
|
+
alter_attributes_for_paper_trail!(:serialize, attributes)
|
53
121
|
end
|
54
122
|
|
55
123
|
def unserialize_attributes_for_paper_trail!(attributes)
|
56
|
-
alter_attributes_for_paper_trail!(
|
124
|
+
alter_attributes_for_paper_trail!(:deserialize, attributes)
|
57
125
|
end
|
58
126
|
|
59
|
-
def alter_attributes_for_paper_trail!(
|
127
|
+
def alter_attributes_for_paper_trail!(serialization_method, attributes)
|
60
128
|
# Don't serialize before values before inserting into columns of type
|
61
129
|
# `JSON` on `PostgreSQL` databases.
|
62
130
|
return attributes if paper_trail_version_class.object_col_is_json?
|
63
131
|
|
132
|
+
serializer = CastedAttributeSerializer.new(self)
|
64
133
|
attributes.each do |key, value|
|
65
|
-
attributes[key] =
|
134
|
+
attributes[key] = serializer.send(serialization_method, key, value)
|
66
135
|
end
|
67
136
|
end
|
68
137
|
|
69
138
|
# Used for Version#object_changes attribute.
|
70
139
|
def serialize_attribute_changes_for_paper_trail!(changes)
|
71
|
-
alter_attribute_changes_for_paper_trail!(
|
140
|
+
alter_attribute_changes_for_paper_trail!(:serialize, changes)
|
72
141
|
end
|
73
142
|
|
74
143
|
def unserialize_attribute_changes_for_paper_trail!(changes)
|
75
|
-
alter_attribute_changes_for_paper_trail!(
|
144
|
+
alter_attribute_changes_for_paper_trail!(:deserialize, changes)
|
76
145
|
end
|
77
146
|
|
78
|
-
def alter_attribute_changes_for_paper_trail!(
|
147
|
+
def alter_attribute_changes_for_paper_trail!(serialization_method, changes)
|
79
148
|
# Don't serialize before values before inserting into columns of type
|
80
149
|
# `JSON` on `PostgreSQL` databases.
|
81
150
|
return changes if paper_trail_version_class.object_changes_col_is_json?
|
82
151
|
|
152
|
+
serializer = CastedAttributeSerializer.new(self)
|
83
153
|
changes.clone.each do |key, change|
|
84
|
-
|
85
|
-
changes[key] = Array(change).map
|
154
|
+
# `change` is an Array with two elements, representing before and after.
|
155
|
+
changes[key] = Array(change).map do |value|
|
156
|
+
serializer.send(serialization_method, key, value)
|
157
|
+
end
|
86
158
|
end
|
87
159
|
end
|
88
160
|
end
|
data/lib/paper_trail/cleaner.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module PaperTrail
|
2
|
+
# Utilities for deleting version records.
|
2
3
|
module Cleaner
|
3
4
|
# Destroys all but the most recent version(s) for items on a given date
|
4
5
|
# (or on all dates). Useful for deleting drafts.
|
@@ -6,7 +7,8 @@ module PaperTrail
|
|
6
7
|
# Options:
|
7
8
|
#
|
8
9
|
# - :keeping - An `integer` indicating the number of versions to be kept for
|
9
|
-
# each item per date. Defaults to `1`.
|
10
|
+
# each item per date. Defaults to `1`. The most recent matching versions
|
11
|
+
# are kept.
|
10
12
|
# - :date - Should either be a `Date` object specifying which date to
|
11
13
|
# destroy versions for or `:all`, which will specify that all dates
|
12
14
|
# should be cleaned. Defaults to `:all`.
|
@@ -14,13 +16,13 @@ module PaperTrail
|
|
14
16
|
# causes all items to be cleaned. Defaults to `nil`.
|
15
17
|
#
|
16
18
|
def clean_versions!(options = {})
|
17
|
-
options = {:
|
18
|
-
gather_versions(options[:item_id], options[:date]).each do |
|
19
|
-
group_versions_by_date(
|
19
|
+
options = { keeping: 1, date: :all }.merge(options)
|
20
|
+
gather_versions(options[:item_id], options[:date]).each do |_item_id, item_versions|
|
21
|
+
group_versions_by_date(item_versions).each do |_date, date_versions|
|
20
22
|
# Remove the number of versions we wish to keep from the collection
|
21
23
|
# of versions prior to destruction.
|
22
|
-
|
23
|
-
|
24
|
+
date_versions.pop(options[:keeping])
|
25
|
+
date_versions.map(&:destroy)
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -30,10 +32,14 @@ module PaperTrail
|
|
30
32
|
# Returns a hash of versions grouped by the `item_id` attribute formatted
|
31
33
|
# like this: {:item_id => PaperTrail::Version}. If `item_id` or `date` is
|
32
34
|
# set, versions will be narrowed to those pointing at items with those ids
|
33
|
-
# that were created on specified date.
|
35
|
+
# that were created on specified date. Versions are returned in
|
36
|
+
# chronological order.
|
34
37
|
def gather_versions(item_id = nil, date = :all)
|
35
|
-
|
36
|
-
|
38
|
+
unless date == :all || date.respond_to?(:to_date)
|
39
|
+
raise ArgumentError, "Expected date to be a Timestamp or :all"
|
40
|
+
end
|
41
|
+
versions = item_id ? PaperTrail::Version.where(item_id: item_id) : PaperTrail::Version
|
42
|
+
versions = versions.order(PaperTrail::Version.timestamp_sort_order)
|
37
43
|
versions = versions.between(date.to_date, date.to_date + 1.day) unless date == :all
|
38
44
|
|
39
45
|
# If `versions` has not been converted to an ActiveRecord::Relation yet,
|
data/lib/paper_trail/config.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
|
-
require
|
2
|
-
require
|
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
10
|
attr_writer :track_associations
|
9
11
|
|
10
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.
|
11
18
|
@timestamp_field = :created_at
|
12
|
-
@serializer
|
19
|
+
@serializer = PaperTrail::Serializers::YAML
|
13
20
|
end
|
14
21
|
|
15
22
|
def serialized_attributes
|
@@ -27,21 +34,31 @@ module PaperTrail
|
|
27
34
|
)
|
28
35
|
end
|
29
36
|
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
33
51
|
@track_associations
|
52
|
+
end
|
34
53
|
end
|
35
|
-
alias_method :track_associations?, :track_associations
|
36
54
|
|
37
55
|
# Indicates whether PaperTrail is on or off. Default: true.
|
38
56
|
def enabled
|
39
|
-
|
40
|
-
value.nil? ? true : value
|
57
|
+
@mutex.synchronize { !!@enabled }
|
41
58
|
end
|
42
59
|
|
43
|
-
def enabled=
|
44
|
-
|
60
|
+
def enabled=(enable)
|
61
|
+
@mutex.synchronize { @enabled = enable }
|
45
62
|
end
|
46
63
|
end
|
47
64
|
end
|
@@ -2,3 +2,7 @@
|
|
2
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"
|
5
|
+
|
6
|
+
ActiveSupport.on_load(:active_record) do
|
7
|
+
include PaperTrail::Model
|
8
|
+
end
|
@@ -1,6 +1,10 @@
|
|
1
|
-
require
|
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
|
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,23 +1,26 @@
|
|
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
8
|
before = [
|
7
9
|
:set_paper_trail_enabled_for_controller,
|
8
|
-
:set_paper_trail_whodunnit,
|
9
10
|
:set_paper_trail_controller_info
|
10
11
|
]
|
11
|
-
after = [
|
12
|
+
after = [
|
13
|
+
:warn_about_not_setting_whodunnit
|
14
|
+
]
|
12
15
|
|
13
16
|
if base.respond_to? :before_action
|
14
17
|
# Rails 4+
|
15
|
-
before.map {|sym| base.before_action sym }
|
16
|
-
after.map {|sym| base.after_action sym }
|
18
|
+
before.map { |sym| base.before_action sym }
|
19
|
+
after.map { |sym| base.after_action sym }
|
17
20
|
else
|
18
21
|
# Rails 3.
|
19
|
-
before.map {|sym| base.before_filter sym }
|
20
|
-
after.map {|sym| base.after_filter sym }
|
22
|
+
before.map { |sym| base.before_filter sym }
|
23
|
+
after.map { |sym| base.after_filter sym }
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
@@ -76,6 +79,7 @@ module PaperTrail
|
|
76
79
|
|
77
80
|
# Tells PaperTrail who is responsible for any changes that occur.
|
78
81
|
def set_paper_trail_whodunnit
|
82
|
+
@set_paper_trail_whodunnit_called = true
|
79
83
|
::PaperTrail.whodunnit = user_for_paper_trail if ::PaperTrail.enabled_for_controller?
|
80
84
|
end
|
81
85
|
|
@@ -85,10 +89,26 @@ module PaperTrail
|
|
85
89
|
::PaperTrail.controller_info = info_for_paper_trail if ::PaperTrail.enabled_for_controller?
|
86
90
|
end
|
87
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
|
+
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
|
100
|
+
before_filter for you. Please add this before_filter to your
|
101
|
+
ApplicationController to continue recording whodunnit. See the
|
102
|
+
PaperTrail readme for an example.
|
103
|
+
EOS
|
104
|
+
end
|
105
|
+
end
|
88
106
|
end
|
89
107
|
end
|
108
|
+
end
|
90
109
|
|
91
|
-
|
92
|
-
|
110
|
+
if defined?(::ActionController)
|
111
|
+
::ActiveSupport.on_load(:action_controller) do
|
112
|
+
include ::PaperTrail::Rails::Controller
|
93
113
|
end
|
94
114
|
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
module PaperTrail
|
2
2
|
module Rails
|
3
|
+
# See http://guides.rubyonrails.org/engines.html
|
3
4
|
class Engine < ::Rails::Engine
|
4
|
-
paths[
|
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
|
+
ActiveRecord::Base.send :include, PaperTrail::Model
|
9
|
+
PaperTrail.enabled = app.config.paper_trail.fetch(:enabled, true)
|
10
|
+
end
|
5
11
|
end
|
6
12
|
end
|
7
13
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
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, :
|
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.
|
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,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
|
20
|
+
context "with versioning", versioning: true do
|
19
21
|
class_exec(&block)
|
20
22
|
end
|
21
23
|
end
|