mongo_trails 10.3.1 → 14.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/.github/workflows/test.yml +53 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/Appraisals +10 -4
- data/Gemfile +8 -1
- data/README.md +27 -6
- data/Rakefile +17 -0
- data/gemfiles/rails_7.gemfile +15 -0
- data/gemfiles/rails_7.gemfile.lock +212 -0
- data/gemfiles/rails_8.gemfile +15 -0
- data/gemfiles/rails_8.gemfile.lock +213 -0
- data/gemfiles/rails_8_1.gemfile +15 -0
- data/gemfiles/rails_8_1.gemfile.lock +143 -0
- data/lib/mongo_trails/callback_propagation.rb +77 -0
- data/lib/mongo_trails/config.rb +7 -24
- data/lib/mongo_trails/events/base.rb +5 -308
- data/lib/mongo_trails/model_config.rb +1 -232
- data/lib/mongo_trails/mongo_support/config.rb +7 -1
- data/lib/mongo_trails/mongo_support/criteria.rb +7 -0
- data/lib/mongo_trails/mongo_support/version.rb +242 -19
- data/lib/mongo_trails/mongo_support/version_commit_wrap.rb +37 -0
- data/lib/mongo_trails/mongo_support/write_version_worker.rb +11 -0
- data/lib/mongo_trails/record_trail.rb +21 -262
- data/lib/mongo_trails/version.rb +5 -0
- data/lib/mongo_trails/version_concern.rb +4 -293
- data/lib/mongo_trails.rb +13 -149
- data/mongo_trails.gemspec +19 -20
- metadata +50 -85
- data/.travis.yml +0 -13
- data/Gemfile.lock +0 -62
- data/gemfiles/rails_5.gemfile +0 -9
- data/gemfiles/rails_5.gemfile.lock +0 -63
- data/gemfiles/rails_6.gemfile +0 -9
- data/gemfiles/rails_6.gemfile.lock +0 -63
- data/lib/mongo_trails/attribute_serializers/README.md +0 -10
- data/lib/mongo_trails/attribute_serializers/attribute_serializer_factory.rb +0 -27
- data/lib/mongo_trails/attribute_serializers/cast_attribute_serializer.rb +0 -51
- data/lib/mongo_trails/attribute_serializers/object_attribute.rb +0 -41
- data/lib/mongo_trails/attribute_serializers/object_changes_attribute.rb +0 -44
- data/lib/mongo_trails/cleaner.rb +0 -60
- data/lib/mongo_trails/compatibility.rb +0 -51
- data/lib/mongo_trails/events/create.rb +0 -32
- data/lib/mongo_trails/events/destroy.rb +0 -42
- data/lib/mongo_trails/events/update.rb +0 -60
- data/lib/mongo_trails/frameworks/cucumber.rb +0 -33
- data/lib/mongo_trails/frameworks/rails/controller.rb +0 -109
- data/lib/mongo_trails/frameworks/rails/engine.rb +0 -43
- data/lib/mongo_trails/frameworks/rails.rb +0 -4
- data/lib/mongo_trails/frameworks/rspec/helpers.rb +0 -29
- data/lib/mongo_trails/frameworks/rspec.rb +0 -43
- data/lib/mongo_trails/has_paper_trail.rb +0 -86
- data/lib/mongo_trails/queries/versions/where_object.rb +0 -65
- data/lib/mongo_trails/queries/versions/where_object_changes.rb +0 -75
- data/lib/mongo_trails/record_history.rb +0 -51
- data/lib/mongo_trails/reifier.rb +0 -130
- data/lib/mongo_trails/request.rb +0 -166
- data/lib/mongo_trails/serializers/json.rb +0 -46
- data/lib/mongo_trails/serializers/yaml.rb +0 -43
- data/lib/mongo_trails/type_serializers/postgres_array_serializer.rb +0 -48
- data/lib/mongo_trails/version_number.rb +0 -23
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "mongo_trails/attribute_serializers/object_attribute"
|
|
4
|
-
require "mongo_trails/attribute_serializers/object_changes_attribute"
|
|
5
|
-
require "mongo_trails/model_config"
|
|
6
|
-
require "mongo_trails/record_trail"
|
|
7
|
-
|
|
8
|
-
module PaperTrail
|
|
9
|
-
# Extensions to `ActiveRecord::Base`. See `frameworks/active_record.rb`.
|
|
10
|
-
# It is our goal to have the smallest possible footprint here, because
|
|
11
|
-
# `ActiveRecord::Base` is a very crowded namespace! That is why we introduced
|
|
12
|
-
# `.paper_trail` and `#paper_trail`.
|
|
13
|
-
module Model
|
|
14
|
-
def self.included(base)
|
|
15
|
-
base.send :extend, ClassMethods
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# :nodoc:
|
|
19
|
-
module ClassMethods
|
|
20
|
-
# Declare this in your model to track every create, update, and destroy.
|
|
21
|
-
# Each version of the model is available in the `versions` association.
|
|
22
|
-
#
|
|
23
|
-
# Options:
|
|
24
|
-
#
|
|
25
|
-
# - :on - The events to track (optional; defaults to all of them). Set
|
|
26
|
-
# to an array of `:create`, `:update`, `:destroy` and `:touch` as desired.
|
|
27
|
-
# - :class_name (deprecated) - The name of a custom Version class that
|
|
28
|
-
# includes `PaperTrail::VersionConcern`.
|
|
29
|
-
# - :ignore - An array of attributes for which a new `Version` will not be
|
|
30
|
-
# created if only they change. It can also accept a Hash as an
|
|
31
|
-
# argument where the key is the attribute to ignore (a `String` or
|
|
32
|
-
# `Symbol`), which will only be ignored if the value is a `Proc` which
|
|
33
|
-
# returns truthily.
|
|
34
|
-
# - :if, :unless - Procs that allow to specify conditions when to save
|
|
35
|
-
# versions for an object.
|
|
36
|
-
# - :only - Inverse of `ignore`. A new `Version` will be created only
|
|
37
|
-
# for these attributes if supplied it can also accept a Hash as an
|
|
38
|
-
# argument where the key is the attribute to track (a `String` or
|
|
39
|
-
# `Symbol`), which will only be counted if the value is a `Proc` which
|
|
40
|
-
# returns truthily.
|
|
41
|
-
# - :skip - Fields to ignore completely. As with `ignore`, updates to
|
|
42
|
-
# these fields will not create a new `Version`. In addition, these
|
|
43
|
-
# fields will not be included in the serialized versions of the object
|
|
44
|
-
# whenever a new `Version` is created.
|
|
45
|
-
# - :meta - A hash of extra data to store. You must add a column to the
|
|
46
|
-
# `versions` table for each key. Values are objects or procs (which
|
|
47
|
-
# are called with `self`, i.e. the model with the paper trail). See
|
|
48
|
-
# `PaperTrail::Controller.info_for_paper_trail` for how to store data
|
|
49
|
-
# from the controller.
|
|
50
|
-
# - :versions - Either,
|
|
51
|
-
# - A String (deprecated) - The name to use for the versions
|
|
52
|
-
# association. Default is `:versions`.
|
|
53
|
-
# - A Hash - options passed to `has_many`, plus `name:` and `scope:`.
|
|
54
|
-
# - :version - The name to use for the method which returns the version
|
|
55
|
-
# the instance was reified from. Default is `:version`.
|
|
56
|
-
#
|
|
57
|
-
# Plugins like the experimental `paper_trail-association_tracking` gem
|
|
58
|
-
# may accept additional options.
|
|
59
|
-
#
|
|
60
|
-
# You can define a default set of options via the configurable
|
|
61
|
-
# `PaperTrail.config.has_paper_trail_defaults` hash in your applications
|
|
62
|
-
# initializer. The hash can contain any of the following options and will
|
|
63
|
-
# provide an overridable default for all models.
|
|
64
|
-
#
|
|
65
|
-
# @api public
|
|
66
|
-
def has_paper_trail(options = {})
|
|
67
|
-
defaults = PaperTrail.config.has_paper_trail_defaults
|
|
68
|
-
paper_trail.setup(defaults.merge(options))
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# @api public
|
|
72
|
-
def paper_trail
|
|
73
|
-
::PaperTrail::ModelConfig.new(self)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Wrap the following methods in a module so we can include them only in the
|
|
78
|
-
# ActiveRecord models that declare `has_paper_trail`.
|
|
79
|
-
module InstanceMethods
|
|
80
|
-
# @api public
|
|
81
|
-
def paper_trail
|
|
82
|
-
::PaperTrail::RecordTrail.new(self)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
module Queries
|
|
5
|
-
module Versions
|
|
6
|
-
# For public API documentation, see `where_object` in
|
|
7
|
-
# `mongo_trails/version_concern.rb`.
|
|
8
|
-
# @api private
|
|
9
|
-
class WhereObject
|
|
10
|
-
# - version_model_class - The class that VersionConcern was mixed into.
|
|
11
|
-
# - attributes - A `Hash` of attributes and values. See the public API
|
|
12
|
-
# documentation for details.
|
|
13
|
-
# @api private
|
|
14
|
-
def initialize(version_model_class, attributes)
|
|
15
|
-
@version_model_class = version_model_class
|
|
16
|
-
@attributes = attributes
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# @api private
|
|
20
|
-
def execute
|
|
21
|
-
column = @version_model_class.columns_hash["object"]
|
|
22
|
-
raise "where_object can't be called without an object column" unless column
|
|
23
|
-
|
|
24
|
-
case column.type
|
|
25
|
-
when :jsonb
|
|
26
|
-
jsonb
|
|
27
|
-
when :json
|
|
28
|
-
json
|
|
29
|
-
else
|
|
30
|
-
text
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
# @api private
|
|
37
|
-
def json
|
|
38
|
-
predicates = []
|
|
39
|
-
values = []
|
|
40
|
-
@attributes.each do |field, value|
|
|
41
|
-
predicates.push "object->>? = ?"
|
|
42
|
-
values.concat([field, value.to_s])
|
|
43
|
-
end
|
|
44
|
-
sql = predicates.join(" and ")
|
|
45
|
-
@version_model_class.where(sql, *values)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# @api private
|
|
49
|
-
def jsonb
|
|
50
|
-
@version_model_class.where("object @> ?", @attributes.to_json)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# @api private
|
|
54
|
-
def text
|
|
55
|
-
arel_field = @version_model_class.arel_table[:object]
|
|
56
|
-
where_conditions = @attributes.map { |field, value|
|
|
57
|
-
::PaperTrail.serializer.where_object_condition(arel_field, field, value)
|
|
58
|
-
}
|
|
59
|
-
where_conditions = where_conditions.reduce { |a, e| a.and(e) }
|
|
60
|
-
@version_model_class.where(where_conditions)
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
module Queries
|
|
5
|
-
module Versions
|
|
6
|
-
# For public API documentation, see `where_object_changes` in
|
|
7
|
-
# `mongo_trails/version_concern.rb`.
|
|
8
|
-
# @api private
|
|
9
|
-
class WhereObjectChanges
|
|
10
|
-
# - version_model_class - The class that VersionConcern was mixed into.
|
|
11
|
-
# - attributes - A `Hash` of attributes and values. See the public API
|
|
12
|
-
# documentation for details.
|
|
13
|
-
# @api private
|
|
14
|
-
def initialize(version_model_class, attributes)
|
|
15
|
-
@version_model_class = version_model_class
|
|
16
|
-
|
|
17
|
-
# Currently, this `deep_dup` is necessary because the `jsonb` branch
|
|
18
|
-
# modifies `@attributes`, and that would be a nasty suprise for
|
|
19
|
-
# consumers of this class.
|
|
20
|
-
# TODO: Stop modifying `@attributes`, then remove `deep_dup`.
|
|
21
|
-
@attributes = attributes.deep_dup
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# @api private
|
|
25
|
-
def execute
|
|
26
|
-
if PaperTrail.config.object_changes_adapter&.respond_to?(:where_object_changes)
|
|
27
|
-
return PaperTrail.config.object_changes_adapter.where_object_changes(
|
|
28
|
-
@version_model_class, @attributes
|
|
29
|
-
)
|
|
30
|
-
end
|
|
31
|
-
case @version_model_class.columns_hash["object_changes"].type
|
|
32
|
-
when :jsonb
|
|
33
|
-
jsonb
|
|
34
|
-
when :json
|
|
35
|
-
json
|
|
36
|
-
else
|
|
37
|
-
text
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
# @api private
|
|
44
|
-
def json
|
|
45
|
-
predicates = []
|
|
46
|
-
values = []
|
|
47
|
-
@attributes.each do |field, value|
|
|
48
|
-
predicates.push(
|
|
49
|
-
"((object_changes->>? ILIKE ?) OR (object_changes->>? ILIKE ?))"
|
|
50
|
-
)
|
|
51
|
-
values.concat([field, "[#{value.to_json},%", field, "[%,#{value.to_json}]%"])
|
|
52
|
-
end
|
|
53
|
-
sql = predicates.join(" and ")
|
|
54
|
-
@version_model_class.where(sql, *values)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# @api private
|
|
58
|
-
def jsonb
|
|
59
|
-
@attributes.each { |field, value| @attributes[field] = [value] }
|
|
60
|
-
@version_model_class.where("object_changes @> ?", @attributes.to_json)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# @api private
|
|
64
|
-
def text
|
|
65
|
-
arel_field = @version_model_class.arel_table[:object_changes]
|
|
66
|
-
where_conditions = @attributes.map { |field, value|
|
|
67
|
-
::PaperTrail.serializer.where_object_changes_condition(arel_field, field, value)
|
|
68
|
-
}
|
|
69
|
-
where_conditions = where_conditions.reduce { |a, e| a.and(e) }
|
|
70
|
-
@version_model_class.where(where_conditions)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
# Represents the history of a single record.
|
|
5
|
-
# @api private
|
|
6
|
-
class RecordHistory
|
|
7
|
-
# @param versions - ActiveRecord::Relation - All versions of the record.
|
|
8
|
-
# @param version_class - Class - Usually PaperTrail::Version,
|
|
9
|
-
# but it could also be a custom version class.
|
|
10
|
-
# @api private
|
|
11
|
-
def initialize(versions, version_class)
|
|
12
|
-
@versions = versions
|
|
13
|
-
@version_class = version_class
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Returns ordinal position of `version` in `sequence`.
|
|
17
|
-
# @api private
|
|
18
|
-
def index(version)
|
|
19
|
-
sequence.to_a.index(version)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
# Returns `@versions` in chronological order.
|
|
25
|
-
# @api private
|
|
26
|
-
def sequence
|
|
27
|
-
if @version_class.primary_key_is_int?
|
|
28
|
-
@versions.select(primary_key).order(primary_key.asc)
|
|
29
|
-
else
|
|
30
|
-
@versions.
|
|
31
|
-
select([table[:created_at], primary_key]).
|
|
32
|
-
order(@version_class.timestamp_sort_order)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# @return - Arel::Attribute - Attribute representing the primary key
|
|
37
|
-
# of the version table. The column's data type is usually a serial
|
|
38
|
-
# integer (the rails convention) but not always.
|
|
39
|
-
# @api private
|
|
40
|
-
def primary_key
|
|
41
|
-
table[@version_class.primary_key]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# @return - Arel::Table - The version table, usually named `versions`, but
|
|
45
|
-
# not always.
|
|
46
|
-
# @api private
|
|
47
|
-
def table
|
|
48
|
-
@version_class.arel_table
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
data/lib/mongo_trails/reifier.rb
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "mongo_trails/attribute_serializers/object_attribute"
|
|
4
|
-
|
|
5
|
-
module PaperTrail
|
|
6
|
-
# Given a version record and some options, builds a new model object.
|
|
7
|
-
# @api private
|
|
8
|
-
module Reifier
|
|
9
|
-
class << self
|
|
10
|
-
# See `VersionConcern#reify` for documentation.
|
|
11
|
-
# @api private
|
|
12
|
-
def reify(version, options)
|
|
13
|
-
options = apply_defaults_to(options, version)
|
|
14
|
-
attrs = version.object_deserialized
|
|
15
|
-
model = init_model(attrs, options, version)
|
|
16
|
-
reify_attributes(model, version, attrs)
|
|
17
|
-
model.send "#{model.class.version_association_name}=", version
|
|
18
|
-
model
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
# Given a hash of `options` for `.reify`, return a new hash with default
|
|
24
|
-
# values applied.
|
|
25
|
-
# @api private
|
|
26
|
-
def apply_defaults_to(options, version)
|
|
27
|
-
{
|
|
28
|
-
version_at: version.created_at,
|
|
29
|
-
mark_for_destruction: false,
|
|
30
|
-
has_one: false,
|
|
31
|
-
has_many: false,
|
|
32
|
-
belongs_to: false,
|
|
33
|
-
has_and_belongs_to_many: false,
|
|
34
|
-
unversioned_attributes: :nil
|
|
35
|
-
}.merge(options)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Initialize a model object suitable for reifying `version` into. Does
|
|
39
|
-
# not perform reification, merely instantiates the appropriate model
|
|
40
|
-
# class and, if specified by `options[:unversioned_attributes]`, sets
|
|
41
|
-
# unversioned attributes to `nil`.
|
|
42
|
-
#
|
|
43
|
-
# Normally a polymorphic belongs_to relationship allows us to get the
|
|
44
|
-
# object we belong to by calling, in this case, `item`. However this
|
|
45
|
-
# returns nil if `item` has been destroyed, and we need to be able to
|
|
46
|
-
# retrieve destroyed objects.
|
|
47
|
-
#
|
|
48
|
-
# In this situation we constantize the `item_type` to get hold of the
|
|
49
|
-
# class...except when the stored object's attributes include a `type`
|
|
50
|
-
# key. If this is the case, the object we belong to is using single
|
|
51
|
-
# table inheritance (STI) and the `item_type` will be the base class,
|
|
52
|
-
# not the actual subclass. If `type` is present but empty, the class is
|
|
53
|
-
# the base class.
|
|
54
|
-
def init_model(attrs, options, version)
|
|
55
|
-
klass = version_reification_class(version, attrs)
|
|
56
|
-
|
|
57
|
-
# The `dup` option and destroyed version always returns a new object,
|
|
58
|
-
# otherwise we should attempt to load item or to look for the item
|
|
59
|
-
# outside of default scope(s).
|
|
60
|
-
model = if options[:dup] == true || version.event == "destroy"
|
|
61
|
-
klass.new
|
|
62
|
-
else
|
|
63
|
-
find_cond = { klass.primary_key => version.item_id }
|
|
64
|
-
|
|
65
|
-
version.item || klass.unscoped.where(find_cond).first || klass.new
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
if options[:unversioned_attributes] == :nil && !model.new_record?
|
|
69
|
-
init_unversioned_attrs(attrs, model)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
model
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Look for attributes that exist in `model` and not in this version.
|
|
76
|
-
# These attributes should be set to nil. Modifies `attrs`.
|
|
77
|
-
# @api private
|
|
78
|
-
def init_unversioned_attrs(attrs, model)
|
|
79
|
-
(model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Reify onto `model` an attribute named `k` with value `v` from `version`.
|
|
83
|
-
#
|
|
84
|
-
# `ObjectAttribute#deserialize` will return the mapped enum value and in
|
|
85
|
-
# Rails < 5, the []= uses the integer type caster from the column
|
|
86
|
-
# definition (in general) and thus will turn a (usually) string to 0
|
|
87
|
-
# instead of the correct value.
|
|
88
|
-
#
|
|
89
|
-
# @api private
|
|
90
|
-
def reify_attribute(k, v, model, version)
|
|
91
|
-
if model.has_attribute?(k)
|
|
92
|
-
model[k.to_sym] = v
|
|
93
|
-
elsif model.respond_to?("#{k}=")
|
|
94
|
-
model.send("#{k}=", v)
|
|
95
|
-
elsif version.logger
|
|
96
|
-
version.logger.warn(
|
|
97
|
-
"Attribute #{k} does not exist on #{version.item_type} (Version id: #{version.id})."
|
|
98
|
-
)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Reify onto `model` all the attributes of `version`.
|
|
103
|
-
# @api private
|
|
104
|
-
def reify_attributes(model, version, attrs)
|
|
105
|
-
AttributeSerializers::ObjectAttribute.new(model.class).deserialize(attrs)
|
|
106
|
-
attrs.each do |k, v|
|
|
107
|
-
reify_attribute(k, v, model, version)
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Given a `version`, return the class to reify. This method supports
|
|
112
|
-
# Single Table Inheritance (STI) with custom inheritance columns.
|
|
113
|
-
#
|
|
114
|
-
# For example, imagine a `version` whose `item_type` is "Animal". The
|
|
115
|
-
# `animals` table is an STI table (it has cats and dogs) and it has a
|
|
116
|
-
# custom inheritance column, `species`. If `attrs["species"]` is "Dog",
|
|
117
|
-
# this method returns the constant `Dog`. If `attrs["species"]` is blank,
|
|
118
|
-
# this method returns the constant `Animal`. You can see this particular
|
|
119
|
-
# example in action in `spec/models/animal_spec.rb`.
|
|
120
|
-
#
|
|
121
|
-
# TODO: Duplication: similar `constantize` in VersionConcern#version_limit
|
|
122
|
-
def version_reification_class(version, attrs)
|
|
123
|
-
inheritance_column_name = version.item_type.constantize.inheritance_column
|
|
124
|
-
inher_col_value = attrs[inheritance_column_name]
|
|
125
|
-
class_name = inher_col_value.blank? ? version.item_type : inher_col_value
|
|
126
|
-
class_name.constantize
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
end
|
data/lib/mongo_trails/request.rb
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "request_store"
|
|
4
|
-
|
|
5
|
-
module PaperTrail
|
|
6
|
-
# Manages variables that affect the current HTTP request, such as `whodunnit`.
|
|
7
|
-
#
|
|
8
|
-
# Please do not use `PaperTrail::Request` directly, use `PaperTrail.request`.
|
|
9
|
-
# Currently, `Request` is a `Module`, but in the future it is quite possible
|
|
10
|
-
# we may make it a `Class`. If we make such a choice, we will not provide any
|
|
11
|
-
# warning and will not treat it as a breaking change. You've been warned :)
|
|
12
|
-
#
|
|
13
|
-
# @api private
|
|
14
|
-
module Request
|
|
15
|
-
class InvalidOption < RuntimeError
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class << self
|
|
19
|
-
# Sets any data from the controller that you want PaperTrail to store.
|
|
20
|
-
# See also `PaperTrail::Rails::Controller#info_for_paper_trail`.
|
|
21
|
-
#
|
|
22
|
-
# PaperTrail.request.controller_info = { ip: request_user_ip }
|
|
23
|
-
# PaperTrail.request.controller_info # => { ip: '127.0.0.1' }
|
|
24
|
-
#
|
|
25
|
-
# @api public
|
|
26
|
-
def controller_info=(value)
|
|
27
|
-
store[:controller_info] = value
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Returns the data from the controller that you want PaperTrail to store.
|
|
31
|
-
# See also `PaperTrail::Rails::Controller#info_for_paper_trail`.
|
|
32
|
-
#
|
|
33
|
-
# PaperTrail.request.controller_info = { ip: request_user_ip }
|
|
34
|
-
# PaperTrail.request.controller_info # => { ip: '127.0.0.1' }
|
|
35
|
-
#
|
|
36
|
-
# @api public
|
|
37
|
-
def controller_info
|
|
38
|
-
store[:controller_info]
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Switches PaperTrail off for the given model.
|
|
42
|
-
# @api public
|
|
43
|
-
def disable_model(model_class)
|
|
44
|
-
enabled_for_model(model_class, false)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Switches PaperTrail on for the given model.
|
|
48
|
-
# @api public
|
|
49
|
-
def enable_model(model_class)
|
|
50
|
-
enabled_for_model(model_class, true)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Sets whether PaperTrail is enabled or disabled for the current request.
|
|
54
|
-
# @api public
|
|
55
|
-
def enabled=(value)
|
|
56
|
-
store[:enabled] = value
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Returns `true` if PaperTrail is enabled for the request, `false` otherwise.
|
|
60
|
-
# See `PaperTrail::Rails::Controller#paper_trail_enabled_for_controller`.
|
|
61
|
-
# @api public
|
|
62
|
-
def enabled?
|
|
63
|
-
!!store[:enabled]
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Sets whether PaperTrail is enabled or disabled for this model in the
|
|
67
|
-
# current request.
|
|
68
|
-
# @api public
|
|
69
|
-
def enabled_for_model(model, value)
|
|
70
|
-
store[:"enabled_for_#{model}"] = value
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Returns `true` if PaperTrail is enabled for this model in the current
|
|
74
|
-
# request, `false` otherwise.
|
|
75
|
-
# @api public
|
|
76
|
-
def enabled_for_model?(model)
|
|
77
|
-
model.include?(::PaperTrail::Model::InstanceMethods) &&
|
|
78
|
-
!!store.fetch(:"enabled_for_#{model}", true)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# @api private
|
|
82
|
-
def merge(options)
|
|
83
|
-
options.to_h.each do |k, v|
|
|
84
|
-
store[k] = v
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# @api private
|
|
89
|
-
def set(options)
|
|
90
|
-
store.clear
|
|
91
|
-
merge(options)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Returns a deep copy of the internal hash from our RequestStore. Keys are
|
|
95
|
-
# all symbols. Values are mostly primitives, but whodunnit can be a Proc.
|
|
96
|
-
# We cannot use Marshal.dump here because it doesn't support Proc. It is
|
|
97
|
-
# unclear exactly how `deep_dup` handles a Proc, but it doesn't complain.
|
|
98
|
-
# @api private
|
|
99
|
-
def to_h
|
|
100
|
-
store.deep_dup
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Temporarily set `options` and execute a block.
|
|
104
|
-
# @api private
|
|
105
|
-
def with(options)
|
|
106
|
-
return unless block_given?
|
|
107
|
-
validate_public_options(options)
|
|
108
|
-
before = to_h
|
|
109
|
-
merge(options)
|
|
110
|
-
yield
|
|
111
|
-
ensure
|
|
112
|
-
set(before)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Sets who is responsible for any changes that occur during request. You
|
|
116
|
-
# would normally use this in a migration or on the console, when working
|
|
117
|
-
# with models directly.
|
|
118
|
-
#
|
|
119
|
-
# `value` is usually a string, the name of a person, but you can set
|
|
120
|
-
# anything that responds to `to_s`. You can also set a Proc, which will
|
|
121
|
-
# not be evaluated until `whodunnit` is called later, usually right before
|
|
122
|
-
# inserting a `Version` record.
|
|
123
|
-
#
|
|
124
|
-
# @api public
|
|
125
|
-
def whodunnit=(value)
|
|
126
|
-
store[:whodunnit] = value
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# Returns who is reponsible for any changes that occur during request.
|
|
130
|
-
#
|
|
131
|
-
# @api public
|
|
132
|
-
def whodunnit
|
|
133
|
-
who = store[:whodunnit]
|
|
134
|
-
who.respond_to?(:call) ? who.call : who
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
private
|
|
138
|
-
|
|
139
|
-
# Returns a Hash, initializing with default values if necessary.
|
|
140
|
-
# @api private
|
|
141
|
-
def store
|
|
142
|
-
RequestStore.store[:paper_trail] ||= {
|
|
143
|
-
enabled: true
|
|
144
|
-
}
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# Provide a helpful error message if someone has a typo in one of their
|
|
148
|
-
# option keys. We don't validate option values here. That's traditionally
|
|
149
|
-
# been handled with casting (`to_s`, `!!`) in the accessor method.
|
|
150
|
-
# @api private
|
|
151
|
-
def validate_public_options(options)
|
|
152
|
-
options.each do |k, _v|
|
|
153
|
-
case k
|
|
154
|
-
when :controller_info,
|
|
155
|
-
/enabled_for_/,
|
|
156
|
-
:enabled,
|
|
157
|
-
:whodunnit
|
|
158
|
-
next
|
|
159
|
-
else
|
|
160
|
-
raise InvalidOption, "Invalid option: #{k}"
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
module Serializers
|
|
5
|
-
# An alternate serializer for, e.g. `versions.object`.
|
|
6
|
-
module JSON
|
|
7
|
-
extend self # makes all instance methods become module methods as well
|
|
8
|
-
|
|
9
|
-
def load(string)
|
|
10
|
-
ActiveSupport::JSON.decode string
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def dump(object)
|
|
14
|
-
ActiveSupport::JSON.encode object
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Returns a SQL LIKE condition to be used to match the given field and
|
|
18
|
-
# value in the serialized object.
|
|
19
|
-
def where_object_condition(arel_field, field, value)
|
|
20
|
-
# Convert to JSON to handle strings and nulls correctly.
|
|
21
|
-
json_value = value.to_json
|
|
22
|
-
|
|
23
|
-
# If the value is a number, we need to ensure that we find the next
|
|
24
|
-
# character too, which is either `,` or `}`, to ensure that searching
|
|
25
|
-
# for the value 12 doesn't yield false positives when the value is
|
|
26
|
-
# 123.
|
|
27
|
-
if value.is_a? Numeric
|
|
28
|
-
arel_field.matches("%\"#{field}\":#{json_value},%").
|
|
29
|
-
or(arel_field.matches("%\"#{field}\":#{json_value}}%"))
|
|
30
|
-
else
|
|
31
|
-
arel_field.matches("%\"#{field}\":#{json_value}%")
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def where_object_changes_condition(*)
|
|
36
|
-
raise <<-STR.squish.freeze
|
|
37
|
-
where_object_changes no longer supports reading JSON from a text
|
|
38
|
-
column. The old implementation was inaccurate, returning more records
|
|
39
|
-
than you wanted. This feature was deprecated in 7.1.0 and removed in
|
|
40
|
-
8.0.0. The json and jsonb datatypes are still supported. See the
|
|
41
|
-
discussion at https://github.com/paper-trail-gem/paper_trail/issues/803
|
|
42
|
-
STR
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "yaml"
|
|
4
|
-
|
|
5
|
-
module PaperTrail
|
|
6
|
-
module Serializers
|
|
7
|
-
# The default serializer for, e.g. `versions.object`.
|
|
8
|
-
module YAML
|
|
9
|
-
extend self # makes all instance methods become module methods as well
|
|
10
|
-
|
|
11
|
-
def load(string)
|
|
12
|
-
::YAML.load string
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
# @param object (Hash | HashWithIndifferentAccess) - Coming from
|
|
16
|
-
# `recordable_object` `object` will be a plain `Hash`. However, due to
|
|
17
|
-
# recent [memory optimizations](https://git.io/fjeYv), when coming from
|
|
18
|
-
# `recordable_object_changes`, it will be a `HashWithIndifferentAccess`.
|
|
19
|
-
def dump(object)
|
|
20
|
-
object = object.to_hash if object.is_a?(HashWithIndifferentAccess)
|
|
21
|
-
::YAML.dump object
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Returns a SQL LIKE condition to be used to match the given field and
|
|
25
|
-
# value in the serialized object.
|
|
26
|
-
def where_object_condition(arel_field, field, value)
|
|
27
|
-
arel_field.matches("%\n#{field}: #{value}\n%")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Returns a SQL LIKE condition to be used to match the given field and
|
|
31
|
-
# value in the serialized `object_changes`.
|
|
32
|
-
def where_object_changes_condition(*)
|
|
33
|
-
raise <<-STR.squish.freeze
|
|
34
|
-
where_object_changes no longer supports reading YAML from a text
|
|
35
|
-
column. The old implementation was inaccurate, returning more records
|
|
36
|
-
than you wanted. This feature was deprecated in 8.1.0 and removed in
|
|
37
|
-
9.0.0. The json and jsonb datatypes are still supported. See
|
|
38
|
-
discussion at https://github.com/paper-trail-gem/paper_trail/pull/997
|
|
39
|
-
STR
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|