paper_trail 6.0.1 → 6.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|