paper_trail 6.0.1 → 6.0.2
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/CONTRIBUTING.md +45 -9
- data/.rubocop_todo.yml +2 -2
- data/CHANGELOG.md +22 -0
- data/README.md +1 -1
- data/lib/paper_trail/model_config.rb +6 -16
- data/lib/paper_trail/queries/versions/where_object.rb +60 -0
- data/lib/paper_trail/queries/versions/where_object_changes.rb +68 -0
- data/lib/paper_trail/record_trail.rb +71 -45
- data/lib/paper_trail/reifier.rb +243 -164
- data/lib/paper_trail/version_concern.rb +48 -48
- data/lib/paper_trail/version_number.rb +1 -1
- data/paper_trail.gemspec +23 -3
- data/spec/controllers/articles_controller_spec.rb +28 -0
- data/test/dummy/config/boot.rb +20 -6
- metadata +16 -11
- data/test/functional/enabled_for_controller_test.rb +0 -28
@@ -1,5 +1,7 @@
|
|
1
1
|
require "active_support/concern"
|
2
2
|
require "paper_trail/attribute_serializers/object_changes_attribute"
|
3
|
+
require "paper_trail/queries/versions/where_object"
|
4
|
+
require "paper_trail/queries/versions/where_object_changes"
|
3
5
|
|
4
6
|
module PaperTrail
|
5
7
|
# Originally, PaperTrail did not provide this module, and all of this
|
@@ -95,62 +97,60 @@ module PaperTrail
|
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
100
|
+
# Given a hash of attributes like `name: 'Joan'`, query the
|
101
|
+
# `versions.objects` column.
|
102
|
+
#
|
103
|
+
# ```
|
104
|
+
# SELECT "versions".*
|
105
|
+
# FROM "versions"
|
106
|
+
# WHERE ("versions"."object" LIKE '%
|
107
|
+
# name: Joan
|
108
|
+
# %')
|
109
|
+
# ```
|
110
|
+
#
|
111
|
+
# This is useful for finding versions where a given attribute had a given
|
112
|
+
# value. Imagine, in the example above, that Joan had changed her name
|
113
|
+
# and we wanted to find the versions before that change.
|
114
|
+
#
|
115
|
+
# Based on the data type of the `object` column, the appropriate SQL
|
116
|
+
# operator is used. For example, a text column will use `like`, and a
|
117
|
+
# jsonb column will use `@>`.
|
118
|
+
#
|
101
119
|
# @api public
|
102
120
|
def where_object(args = {})
|
103
121
|
raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
|
104
|
-
|
105
|
-
if columns_hash["object"].type == :jsonb
|
106
|
-
where("object @> ?", args.to_json)
|
107
|
-
elsif columns_hash["object"].type == :json
|
108
|
-
predicates = []
|
109
|
-
values = []
|
110
|
-
args.each do |field, value|
|
111
|
-
predicates.push "object->>? = ?"
|
112
|
-
values.concat([field, value.to_s])
|
113
|
-
end
|
114
|
-
sql = predicates.join(" and ")
|
115
|
-
where(sql, *values)
|
116
|
-
else
|
117
|
-
arel_field = arel_table[:object]
|
118
|
-
where_conditions = args.map { |field, value|
|
119
|
-
PaperTrail.serializer.where_object_condition(arel_field, field, value)
|
120
|
-
}
|
121
|
-
where_conditions = where_conditions.reduce { |a, e| a.and(e) }
|
122
|
-
where(where_conditions)
|
123
|
-
end
|
122
|
+
Queries::Versions::WhereObject.new(self, args).execute
|
124
123
|
end
|
125
124
|
|
126
|
-
#
|
127
|
-
#
|
125
|
+
# Given a hash of attributes like `name: 'Joan'`, query the
|
126
|
+
# `versions.objects_changes` column.
|
127
|
+
#
|
128
|
+
# ```
|
129
|
+
# SELECT "versions".*
|
130
|
+
# FROM "versions"
|
131
|
+
# WHERE .. ("versions"."object_changes" LIKE '%
|
132
|
+
# name:
|
133
|
+
# - Joan
|
134
|
+
# %' OR "versions"."object_changes" LIKE '%
|
135
|
+
# name:
|
136
|
+
# -%
|
137
|
+
# - Joan
|
138
|
+
# %')
|
139
|
+
# ```
|
140
|
+
#
|
141
|
+
# This is useful for finding versions immediately before and after a given
|
142
|
+
# attribute had a given value. Imagine, in the example above, that someone
|
143
|
+
# changed their name to Joan and we wanted to find the versions
|
144
|
+
# immediately before and after that change.
|
145
|
+
#
|
146
|
+
# Based on the data type of the `object` column, the appropriate SQL
|
147
|
+
# operator is used. For example, a text column will use `like`, and a
|
148
|
+
# jsonb column will use `@>`.
|
149
|
+
#
|
128
150
|
# @api public
|
129
151
|
def where_object_changes(args = {})
|
130
152
|
raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
|
131
|
-
|
132
|
-
if columns_hash["object_changes"].type == :jsonb
|
133
|
-
args.each { |field, value| args[field] = [value] }
|
134
|
-
where("object_changes @> ?", args.to_json)
|
135
|
-
elsif columns_hash["object"].type == :json
|
136
|
-
predicates = []
|
137
|
-
values = []
|
138
|
-
args.each do |field, value|
|
139
|
-
predicates.push(
|
140
|
-
"((object_changes->>? ILIKE ?) OR (object_changes->>? ILIKE ?))"
|
141
|
-
)
|
142
|
-
values.concat([field, "[#{value.to_json},%", field, "[%,#{value.to_json}]%"])
|
143
|
-
end
|
144
|
-
sql = predicates.join(" and ")
|
145
|
-
where(sql, *values)
|
146
|
-
else
|
147
|
-
arel_field = arel_table[:object_changes]
|
148
|
-
where_conditions = args.map { |field, value|
|
149
|
-
PaperTrail.serializer.where_object_changes_condition(arel_field, field, value)
|
150
|
-
}
|
151
|
-
where_conditions = where_conditions.reduce { |a, e| a.and(e) }
|
152
|
-
where(where_conditions)
|
153
|
-
end
|
153
|
+
Queries::Versions::WhereObjectChanges.new(self, args).execute
|
154
154
|
end
|
155
155
|
|
156
156
|
def primary_key_is_int?
|
data/paper_trail.gemspec
CHANGED
@@ -5,8 +5,12 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.name = "paper_trail"
|
6
6
|
s.version = PaperTrail::VERSION::STRING.dup # The `dup` is for ruby 1.9.3
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
|
-
s.summary = "Track changes to your models
|
9
|
-
s.description =
|
8
|
+
s.summary = "Track changes to your models."
|
9
|
+
s.description = <<-EOS
|
10
|
+
Track changes to your models, for auditing or versioning. See how a model looked
|
11
|
+
at any stage in its lifecycle, revert it to any version, or restore it after it
|
12
|
+
has been destroyed.
|
13
|
+
EOS
|
10
14
|
s.homepage = "https://github.com/airblade/paper_trail"
|
11
15
|
s.authors = ["Andy Stewart", "Ben Atkins"]
|
12
16
|
s.email = "batkinz@gmail.com"
|
@@ -28,15 +32,31 @@ Gem::Specification.new do |s|
|
|
28
32
|
s.add_development_dependency "rake", "~> 10.4.2"
|
29
33
|
s.add_development_dependency "shoulda", "~> 3.5.0"
|
30
34
|
s.add_development_dependency "ffaker", "~> 2.1.0"
|
31
|
-
|
35
|
+
|
36
|
+
# Why `railties`? Possibly used by `test/dummy` boot up?
|
37
|
+
s.add_development_dependency "railties", [">= 4.0", "< 5.2"]
|
38
|
+
|
32
39
|
s.add_development_dependency "rack-test", "~> 0.6.3"
|
33
40
|
s.add_development_dependency "rspec-rails", "~> 3.5"
|
34
41
|
s.add_development_dependency "generator_spec", "~> 0.9.3"
|
35
42
|
s.add_development_dependency "database_cleaner", "~> 1.2"
|
36
43
|
s.add_development_dependency "pry-nav", "~> 0.2.4"
|
44
|
+
|
45
|
+
# We cannot upgrade rubocop until we drop support for ruby 1.9.3.
|
46
|
+
# Rubocop 0.42 requires ruby >= 2.0. We could add a conditional, as we do
|
47
|
+
# below for rack and pg, but that means our config files (e.g. `.rubocop.yml`
|
48
|
+
# would have to simultaneously be valid in two different versions of rubocop.
|
49
|
+
# That is currently possible, but probably won't be in the future, and is
|
50
|
+
# not worth the effort.) Because of pain points like this, I think we'll
|
51
|
+
# have to drop support for ruby 1.9.3 soon.
|
37
52
|
s.add_development_dependency "rubocop", "~> 0.41.1"
|
53
|
+
|
38
54
|
s.add_development_dependency "timecop", "~> 0.8.0"
|
39
55
|
|
56
|
+
if ::Gem.ruby_version < ::Gem::Version.new("2.0.0")
|
57
|
+
s.add_development_dependency "rack", "< 2"
|
58
|
+
end
|
59
|
+
|
40
60
|
if defined?(JRUBY_VERSION)
|
41
61
|
s.add_development_dependency "activerecord-jdbcsqlite3-adapter", "~> 1.3.15"
|
42
62
|
s.add_development_dependency "activerecord-jdbcpostgresql-adapter", "~> 1.3.15"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
RSpec.describe ArticlesController, type: :controller do
|
4
|
+
describe "PaperTrail.enabled_for_controller?" do
|
5
|
+
context "PaperTrail.enabled? == true" do
|
6
|
+
before { PaperTrail.enabled = true }
|
7
|
+
|
8
|
+
it "returns true" do
|
9
|
+
assert PaperTrail.enabled?
|
10
|
+
post :create, params_wrapper(article: { title: "Doh", content: FFaker::Lorem.sentence })
|
11
|
+
expect(assigns(:article)).to_not be_nil
|
12
|
+
assert PaperTrail.enabled_for_controller?
|
13
|
+
assert_equal 1, assigns(:article).versions.length
|
14
|
+
end
|
15
|
+
|
16
|
+
after { PaperTrail.enabled = false }
|
17
|
+
end
|
18
|
+
|
19
|
+
context "PaperTrail.enabled? == false" do
|
20
|
+
it "returns false" do
|
21
|
+
assert !PaperTrail.enabled?
|
22
|
+
post :create, params_wrapper(article: { title: "Doh", content: FFaker::Lorem.sentence })
|
23
|
+
assert !PaperTrail.enabled_for_controller?
|
24
|
+
assert_equal 0, assigns(:article).versions.length
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/test/dummy/config/boot.rb
CHANGED
@@ -1,10 +1,24 @@
|
|
1
1
|
require "rubygems"
|
2
|
-
gemfile = File.expand_path("../../../../Gemfile", __FILE__)
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
# We normally use the root project Gemfile (and gemspec), but when we run rake
|
4
|
+
# locally (not on travis) in this dummy app, we set the BUNDLE_GEMFILE env.
|
5
|
+
# variable. The project Gemfile/gemspec allows AR 4.0, which is a problem
|
6
|
+
# because this dummy app uses `enum` in some of its models, and `enum` was
|
7
|
+
# introduced in AR 4.1. So, when we run rake here, we use:
|
8
|
+
#
|
9
|
+
# BUNDLE_GEMFILE=../../gemfiles/ar_4.2.gemfile bundle exec rake
|
10
|
+
#
|
11
|
+
# Once we drop support for AR 4.0 and 4.1 this will be less of a problem, but
|
12
|
+
# we should keep the ability to specify BUNDLE_GEMFILE because the same
|
13
|
+
# situation could come up in the future.
|
14
|
+
unless ENV.key?("BUNDLE_GEMFILE")
|
15
|
+
gemfile = File.expand_path("../../../../Gemfile", __FILE__)
|
16
|
+
if File.exist?(gemfile)
|
17
|
+
puts "Booting PT test dummy app: Using gemfile: #{gemfile}"
|
18
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
19
|
+
end
|
8
20
|
end
|
21
|
+
require "bundler"
|
22
|
+
Bundler.setup
|
9
23
|
|
10
|
-
$LOAD_PATH.unshift
|
24
|
+
$LOAD_PATH.unshift(File.expand_path("../../../../lib", __FILE__))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paper_trail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.
|
4
|
+
version: 6.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Stewart
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-12-
|
12
|
+
date: 2016-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -107,20 +107,20 @@ dependencies:
|
|
107
107
|
requirements:
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '4.0'
|
111
111
|
- - "<"
|
112
112
|
- !ruby/object:Gem::Version
|
113
|
-
version: '
|
113
|
+
version: '5.2'
|
114
114
|
type: :development
|
115
115
|
prerelease: false
|
116
116
|
version_requirements: !ruby/object:Gem::Requirement
|
117
117
|
requirements:
|
118
118
|
- - ">="
|
119
119
|
- !ruby/object:Gem::Version
|
120
|
-
version: '
|
120
|
+
version: '4.0'
|
121
121
|
- - "<"
|
122
122
|
- !ruby/object:Gem::Version
|
123
|
-
version: '
|
123
|
+
version: '5.2'
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: rack-test
|
126
126
|
requirement: !ruby/object:Gem::Requirement
|
@@ -261,7 +261,10 @@ dependencies:
|
|
261
261
|
- - "~>"
|
262
262
|
- !ruby/object:Gem::Version
|
263
263
|
version: 0.4.2
|
264
|
-
description:
|
264
|
+
description: |
|
265
|
+
Track changes to your models, for auditing or versioning. See how a model looked
|
266
|
+
at any stage in its lifecycle, revert it to any version, or restore it after it
|
267
|
+
has been destroyed.
|
265
268
|
email: batkinz@gmail.com
|
266
269
|
executables: []
|
267
270
|
extensions: []
|
@@ -313,6 +316,8 @@ files:
|
|
313
316
|
- lib/paper_trail/frameworks/sinatra.rb
|
314
317
|
- lib/paper_trail/has_paper_trail.rb
|
315
318
|
- lib/paper_trail/model_config.rb
|
319
|
+
- lib/paper_trail/queries/versions/where_object.rb
|
320
|
+
- lib/paper_trail/queries/versions/where_object_changes.rb
|
316
321
|
- lib/paper_trail/record_history.rb
|
317
322
|
- lib/paper_trail/record_trail.rb
|
318
323
|
- lib/paper_trail/reifier.rb
|
@@ -322,6 +327,7 @@ files:
|
|
322
327
|
- lib/paper_trail/version_concern.rb
|
323
328
|
- lib/paper_trail/version_number.rb
|
324
329
|
- paper_trail.gemspec
|
330
|
+
- spec/controllers/articles_controller_spec.rb
|
325
331
|
- spec/generators/install_generator_spec.rb
|
326
332
|
- spec/generators/paper_trail/templates/create_versions_spec.rb
|
327
333
|
- spec/models/animal_spec.rb
|
@@ -425,7 +431,6 @@ files:
|
|
425
431
|
- test/dummy/db/migrate/20110208155312_set_up_test_tables.rb
|
426
432
|
- test/dummy/db/schema.rb
|
427
433
|
- test/functional/controller_test.rb
|
428
|
-
- test/functional/enabled_for_controller_test.rb
|
429
434
|
- test/functional/modular_sinatra_test.rb
|
430
435
|
- test/functional/sinatra_test.rb
|
431
436
|
- test/functional/thread_safety_test.rb
|
@@ -461,11 +466,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
461
466
|
version: 1.3.6
|
462
467
|
requirements: []
|
463
468
|
rubyforge_project:
|
464
|
-
rubygems_version: 2.5.
|
469
|
+
rubygems_version: 2.5.2
|
465
470
|
signing_key:
|
466
471
|
specification_version: 4
|
467
|
-
summary: Track changes to your models
|
472
|
+
summary: Track changes to your models.
|
468
473
|
test_files:
|
474
|
+
- spec/controllers/articles_controller_spec.rb
|
469
475
|
- spec/generators/install_generator_spec.rb
|
470
476
|
- spec/generators/paper_trail/templates/create_versions_spec.rb
|
471
477
|
- spec/models/animal_spec.rb
|
@@ -569,7 +575,6 @@ test_files:
|
|
569
575
|
- test/dummy/db/migrate/20110208155312_set_up_test_tables.rb
|
570
576
|
- test/dummy/db/schema.rb
|
571
577
|
- test/functional/controller_test.rb
|
572
|
-
- test/functional/enabled_for_controller_test.rb
|
573
578
|
- test/functional/modular_sinatra_test.rb
|
574
579
|
- test/functional/sinatra_test.rb
|
575
580
|
- test/functional/thread_safety_test.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class EnabledForControllerTest < ActionController::TestCase
|
4
|
-
tests ArticlesController
|
5
|
-
|
6
|
-
context "`PaperTrail.enabled? == true`" do
|
7
|
-
should "enabled_for_controller?.should == true" do
|
8
|
-
assert PaperTrail.enabled?
|
9
|
-
post :create, params_wrapper(article: { title: "Doh", content: FFaker::Lorem.sentence })
|
10
|
-
assert_not_nil assigns(:article)
|
11
|
-
assert PaperTrail.enabled_for_controller?
|
12
|
-
assert_equal 1, assigns(:article).versions.length
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
context "`PaperTrail.enabled? == false`" do
|
17
|
-
setup { PaperTrail.enabled = false }
|
18
|
-
|
19
|
-
should "enabled_for_controller?.should == false" do
|
20
|
-
assert !PaperTrail.enabled?
|
21
|
-
post :create, params_wrapper(article: { title: "Doh", content: FFaker::Lorem.sentence })
|
22
|
-
assert !PaperTrail.enabled_for_controller?
|
23
|
-
assert_equal 0, assigns(:article).versions.length
|
24
|
-
end
|
25
|
-
|
26
|
-
teardown { PaperTrail.enabled = true }
|
27
|
-
end
|
28
|
-
end
|