paper_trail 4.0.0.beta2 → 4.0.0.rc1
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/.gitignore +2 -0
- data/.travis.yml +9 -7
- data/CHANGELOG.md +38 -2
- data/README.md +30 -12
- data/Rakefile +1 -1
- data/gemfiles/3.0.gemfile +3 -1
- data/lib/generators/paper_trail/install_generator.rb +4 -1
- data/lib/paper_trail/cleaner.rb +1 -1
- data/lib/paper_trail/config.rb +6 -0
- data/lib/paper_trail/frameworks/sinatra.rb +1 -0
- data/lib/paper_trail/has_paper_trail.rb +80 -67
- data/lib/paper_trail/serializers/yaml.rb +2 -1
- data/lib/paper_trail/version_concern.rb +64 -19
- data/lib/paper_trail/version_number.rb +1 -1
- data/lib/paper_trail.rb +7 -3
- data/paper_trail.gemspec +2 -1
- data/spec/models/animal_spec.rb +19 -0
- data/spec/models/boolit_spec.rb +48 -0
- data/spec/models/json_version_spec.rb +80 -0
- data/spec/models/thing_spec.rb +11 -0
- data/spec/models/version_spec.rb +153 -78
- data/spec/models/widget_spec.rb +27 -6
- data/spec/modules/paper_trail_spec.rb +27 -0
- data/spec/requests/articles_spec.rb +0 -2
- data/test/dummy/app/models/animal.rb +2 -0
- data/test/dummy/app/models/boolit.rb +4 -0
- data/test/dummy/app/models/fruit.rb +5 -0
- data/test/dummy/app/models/song.rb +20 -0
- data/test/dummy/app/models/thing.rb +3 -0
- data/test/dummy/app/models/whatchamajigger.rb +4 -0
- data/test/dummy/app/models/widget.rb +1 -0
- data/test/dummy/app/versions/json_version.rb +3 -0
- data/test/dummy/config/initializers/paper_trail.rb +3 -0
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +44 -3
- data/test/dummy/db/schema.rb +13 -4
- data/test/functional/controller_test.rb +4 -2
- data/test/unit/model_test.rb +76 -12
- data/test/unit/serializer_test.rb +3 -3
- metadata +40 -6
@@ -6,11 +6,20 @@ module PaperTrail
|
|
6
6
|
|
7
7
|
included do
|
8
8
|
belongs_to :item, :polymorphic => true
|
9
|
-
|
9
|
+
|
10
|
+
# Since the test suite has test coverage for this, we want to declare the
|
11
|
+
# association when the test suite is running. This makes it pass
|
12
|
+
# when DB is not initialized prior to test runs such as when we run on
|
13
|
+
# Travis CI (there won't be a db in `test/dummy/db/`)
|
14
|
+
if PaperTrail.config.track_associations?
|
15
|
+
has_many :version_associations, :dependent => :destroy
|
16
|
+
end
|
10
17
|
|
11
18
|
validates_presence_of :event
|
12
19
|
|
13
|
-
|
20
|
+
if PaperTrail.active_record_protected_attributes?
|
21
|
+
attr_accessible :item_type, :item_id, :event, :whodunnit, :object, :object_changes, :transaction_id, :created_at
|
22
|
+
end
|
14
23
|
|
15
24
|
after_create :enforce_version_limit!
|
16
25
|
|
@@ -77,12 +86,22 @@ module PaperTrail
|
|
77
86
|
# identically-named method in the serializer being used.
|
78
87
|
def where_object(args = {})
|
79
88
|
raise ArgumentError, 'expected to receive a Hash' unless args.is_a?(Hash)
|
80
|
-
arel_field = arel_table[:object]
|
81
89
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
90
|
+
if columns_hash['object'].type == :jsonb
|
91
|
+
where_conditions = "object @> '#{args.to_json}'::jsonb"
|
92
|
+
elsif columns_hash['object'].type == :json
|
93
|
+
where_conditions = args.map do |field, value|
|
94
|
+
"object->>'#{field}' = '#{value}'"
|
95
|
+
end
|
96
|
+
where_conditions = where_conditions.join(" AND ")
|
97
|
+
else
|
98
|
+
arel_field = arel_table[:object]
|
99
|
+
|
100
|
+
where_conditions = args.map do |field, value|
|
101
|
+
PaperTrail.serializer.where_object_condition(arel_field, field, value)
|
102
|
+
end.reduce do |condition1, condition2|
|
103
|
+
condition1.and(condition2)
|
104
|
+
end
|
86
105
|
end
|
87
106
|
|
88
107
|
where(where_conditions)
|
@@ -90,12 +109,23 @@ module PaperTrail
|
|
90
109
|
|
91
110
|
def where_object_changes(args = {})
|
92
111
|
raise ArgumentError, 'expected to receive a Hash' unless args.is_a?(Hash)
|
93
|
-
arel_field = arel_table[:object_changes]
|
94
112
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
113
|
+
if columns_hash['object_changes'].type == :jsonb
|
114
|
+
args.each { |field, value| args[field] = [value] }
|
115
|
+
where_conditions = "object_changes @> '#{args.to_json}'::jsonb"
|
116
|
+
elsif columns_hash['object'].type == :json
|
117
|
+
where_conditions = args.map do |field, value|
|
118
|
+
"((object_changes->>'#{field}' ILIKE '[#{value.to_json},%') OR (object_changes->>'#{field}' ILIKE '[%,#{value.to_json}]%'))"
|
119
|
+
end
|
120
|
+
where_conditions = where_conditions.join(" AND ")
|
121
|
+
else
|
122
|
+
arel_field = arel_table[:object_changes]
|
123
|
+
|
124
|
+
where_conditions = args.map do |field, value|
|
125
|
+
PaperTrail.serializer.where_object_changes_condition(arel_field, field, value)
|
126
|
+
end.reduce do |condition1, condition2|
|
127
|
+
condition1.and(condition2)
|
128
|
+
end
|
99
129
|
end
|
100
130
|
|
101
131
|
where(where_conditions)
|
@@ -109,12 +139,12 @@ module PaperTrail
|
|
109
139
|
|
110
140
|
# Returns whether the `object` column is using the `json` type supported by PostgreSQL
|
111
141
|
def object_col_is_json?
|
112
|
-
|
142
|
+
[:json, :jsonb].include?(columns_hash['object'].type)
|
113
143
|
end
|
114
144
|
|
115
145
|
# Returns whether the `object_changes` column is using the `json` type supported by PostgreSQL
|
116
146
|
def object_changes_col_is_json?
|
117
|
-
|
147
|
+
[:json, :jsonb].include?(columns_hash['object_changes'].try(:type))
|
118
148
|
end
|
119
149
|
end
|
120
150
|
|
@@ -158,7 +188,7 @@ module PaperTrail
|
|
158
188
|
# `item_type` will be the base class, not the actual subclass.
|
159
189
|
# If `type` is present but empty, the class is the base class.
|
160
190
|
|
161
|
-
if
|
191
|
+
if options[:dup] != true && item
|
162
192
|
model = item
|
163
193
|
# Look for attributes that exist in the model and not in this version. These attributes should be set to nil.
|
164
194
|
(model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
|
@@ -166,17 +196,27 @@ module PaperTrail
|
|
166
196
|
inheritance_column_name = item_type.constantize.inheritance_column
|
167
197
|
class_name = attrs[inheritance_column_name].blank? ? item_type : attrs[inheritance_column_name]
|
168
198
|
klass = class_name.constantize
|
169
|
-
|
199
|
+
# the `dup` option always returns a new object, otherwise we should attempt
|
200
|
+
# to look for the item outside of default scope(s)
|
201
|
+
if options[:dup] || (_item = klass.unscoped.find_by_id(item_id)).nil?
|
202
|
+
model = klass.new
|
203
|
+
else
|
204
|
+
model = _item
|
205
|
+
# Look for attributes that exist in the model and not in this version. These attributes should be set to nil.
|
206
|
+
(model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
|
207
|
+
end
|
170
208
|
end
|
171
209
|
|
172
210
|
if PaperTrail.serialized_attributes?
|
173
|
-
model.class.unserialize_attributes_for_paper_trail attrs
|
211
|
+
model.class.unserialize_attributes_for_paper_trail! attrs
|
174
212
|
end
|
175
213
|
|
176
214
|
# Set all the attributes in this version on the model
|
177
215
|
attrs.each do |k, v|
|
178
216
|
if model.has_attribute?(k)
|
179
217
|
model[k.to_sym] = v
|
218
|
+
elsif model.respond_to?("#{k}=")
|
219
|
+
model.send("#{k}=", v)
|
180
220
|
else
|
181
221
|
logger.warn "Attribute #{k} does not exist on #{item_type} (Version id: #{id})."
|
182
222
|
end
|
@@ -204,7 +244,7 @@ module PaperTrail
|
|
204
244
|
_changes = self.class.object_changes_col_is_json? ? object_changes : PaperTrail.serializer.load(object_changes)
|
205
245
|
@changeset ||= HashWithIndifferentAccess.new(_changes).tap do |changes|
|
206
246
|
if PaperTrail.serialized_attributes?
|
207
|
-
item_type.constantize.
|
247
|
+
item_type.constantize.unserialize_attribute_changes_for_paper_trail!(changes)
|
208
248
|
end
|
209
249
|
end
|
210
250
|
rescue
|
@@ -212,8 +252,13 @@ module PaperTrail
|
|
212
252
|
end
|
213
253
|
|
214
254
|
# Returns who put the item into the state stored in this version.
|
255
|
+
def paper_trail_originator
|
256
|
+
@paper_trail_originator ||= previous.whodunnit rescue nil
|
257
|
+
end
|
258
|
+
|
215
259
|
def originator
|
216
|
-
|
260
|
+
warn "DEPRECATED: use `paper_trail_originator` instead of `originator`. Support for `originator` will be removed in PaperTrail 4.0"
|
261
|
+
self.paper_trail_originator
|
217
262
|
end
|
218
263
|
|
219
264
|
# Returns who changed the item from the state it had in this version.
|
data/lib/paper_trail.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'request_store'
|
2
|
+
|
1
3
|
# Require core library
|
2
4
|
Dir[File.join(File.dirname(__FILE__), 'paper_trail', '*.rb')].each do |file|
|
3
5
|
require File.join('paper_trail', File.basename(file, '.rb'))
|
@@ -118,16 +120,18 @@ module PaperTrail
|
|
118
120
|
# Thread-safe hash to hold PaperTrail's data.
|
119
121
|
# Initializing with needed default values.
|
120
122
|
def self.paper_trail_store
|
121
|
-
|
123
|
+
RequestStore.store[:paper_trail] ||= { :request_enabled_for_controller => true }
|
122
124
|
end
|
123
125
|
|
124
126
|
# Returns PaperTrail's configuration object.
|
125
127
|
def self.config
|
126
128
|
@@config ||= PaperTrail::Config.instance
|
129
|
+
yield @@config if block_given?
|
130
|
+
@@config
|
127
131
|
end
|
128
132
|
|
129
|
-
|
130
|
-
|
133
|
+
class << self
|
134
|
+
alias_method :configure, :config
|
131
135
|
end
|
132
136
|
end
|
133
137
|
|
data/paper_trail.gemspec
CHANGED
@@ -21,11 +21,12 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
s.add_dependency 'activerecord', ['>= 3.0', '< 6.0']
|
23
23
|
s.add_dependency 'activesupport', ['>= 3.0', '< 6.0']
|
24
|
+
s.add_dependency 'request_store', '~> 1.1.0'
|
24
25
|
|
25
26
|
s.add_development_dependency 'rake', '~> 10.1.1'
|
26
27
|
s.add_development_dependency 'shoulda', '~> 3.5'
|
27
28
|
# s.add_development_dependency 'shoulda-matchers', '~> 1.5' # needed for ActiveRecord < 4
|
28
|
-
s.add_development_dependency 'ffaker',
|
29
|
+
s.add_development_dependency 'ffaker', '<= 1.31.0'
|
29
30
|
s.add_development_dependency 'railties', ['>= 3.0', '< 5.0']
|
30
31
|
s.add_development_dependency 'sinatra', '~> 1.0'
|
31
32
|
s.add_development_dependency 'rack-test', '>= 0.6'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Animal, :type => :model do
|
4
|
+
it { is_expected.to be_versioned }
|
5
|
+
|
6
|
+
describe "STI", :versioning => true do
|
7
|
+
it { expect(Animal.inheritance_column).to eq('species') }
|
8
|
+
|
9
|
+
describe "updates to the `inheritance_column`" do
|
10
|
+
subject { Cat.create!(:name => 'Leo') }
|
11
|
+
|
12
|
+
it "should be allowed" do
|
13
|
+
subject.update_attributes(:name => 'Spike', :species => 'Dog')
|
14
|
+
dog = Animal.find(subject.id)
|
15
|
+
expect(dog).to be_instance_of(Dog)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
require Rails.root.join('..', 'custom_json_serializer')
|
3
|
+
|
4
|
+
describe Boolit, :type => :model do
|
5
|
+
it { is_expected.to be_versioned }
|
6
|
+
|
7
|
+
it "has a default scope" do
|
8
|
+
expect(subject.default_scopes).to_not be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Versioning", :versioning => true do
|
12
|
+
subject { Boolit.create! }
|
13
|
+
before { subject.update_attributes!(:name => Faker::Name.name) }
|
14
|
+
|
15
|
+
it "should have versions" do
|
16
|
+
expect(subject.versions.size).to eq(2)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be able to be reified and persisted" do
|
20
|
+
expect { subject.versions.last.reify.save! }.to_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
context "Instance falls out of default scope" do
|
24
|
+
before { subject.update_attributes!(:scoped => false) }
|
25
|
+
|
26
|
+
it "is NOT scoped" do
|
27
|
+
expect(Boolit.first).to be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should still be able to be reified and persisted" do
|
31
|
+
expect { subject.previous_version.save! }.to_not raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with `nil` attributes on the live instance" do
|
35
|
+
before do
|
36
|
+
PaperTrail.serializer = CustomJsonSerializer
|
37
|
+
subject.update_attributes!(:name => nil)
|
38
|
+
subject.update_attributes!(:name => Faker::Name.name)
|
39
|
+
end
|
40
|
+
after { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
41
|
+
|
42
|
+
it "should not overwrite that attribute during the reification process" do
|
43
|
+
expect(subject.previous_version.name).to be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
if JsonVersion.table_exists?
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe JsonVersion, :type => :model do
|
6
|
+
it "should include the `VersionConcern` module to get base functionality" do
|
7
|
+
expect(JsonVersion).to include(PaperTrail::VersionConcern)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "Methods" do
|
11
|
+
describe "Class" do
|
12
|
+
|
13
|
+
describe '#where_object' do
|
14
|
+
it { expect(JsonVersion).to respond_to(:where_object) }
|
15
|
+
|
16
|
+
context "invalid arguments" do
|
17
|
+
it "should raise an error" do
|
18
|
+
expect { JsonVersion.where_object(:foo) }.to raise_error(ArgumentError)
|
19
|
+
expect { JsonVersion.where_object([]) }.to raise_error(ArgumentError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "valid arguments", :versioning => true do
|
24
|
+
let(:fruit_names) { %w(apple orange lemon banana lime coconut strawberry blueberry) }
|
25
|
+
let(:fruit) { Fruit.new }
|
26
|
+
let(:name) { 'pomegranate' }
|
27
|
+
let(:color) { Faker::Color.name }
|
28
|
+
|
29
|
+
before do
|
30
|
+
fruit.update_attributes!(:name => name)
|
31
|
+
fruit.update_attributes!(:name => fruit_names.sample, :color => color)
|
32
|
+
fruit.update_attributes!(:name => fruit_names.sample, :color => Faker::Color.name)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be able to locate versions according to their `object` contents" do
|
36
|
+
expect(JsonVersion.where_object(:name => name)).to eq([fruit.versions[1]])
|
37
|
+
expect(JsonVersion.where_object(:color => color)).to eq([fruit.versions[2]])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#where_object_changes' do
|
43
|
+
it { expect(JsonVersion).to respond_to(:where_object_changes) }
|
44
|
+
|
45
|
+
context "invalid arguments" do
|
46
|
+
it "should raise an error" do
|
47
|
+
expect { JsonVersion.where_object_changes(:foo) }.to raise_error(ArgumentError)
|
48
|
+
expect { JsonVersion.where_object_changes([]) }.to raise_error(ArgumentError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "valid arguments", :versioning => true do
|
53
|
+
let(:fruit_names) { %w(apple orange lemon banana lime strawberry blueberry) }
|
54
|
+
let(:tropical_fruit_names) { %w(coconut pineapple kiwi mango melon) }
|
55
|
+
let(:fruit) { Fruit.new }
|
56
|
+
let(:name) { 'pomegranate' }
|
57
|
+
let(:color) { Faker::Color.name }
|
58
|
+
|
59
|
+
before do
|
60
|
+
fruit.update_attributes!(:name => name)
|
61
|
+
fruit.update_attributes!(:name => tropical_fruit_names.sample, :color => color)
|
62
|
+
fruit.update_attributes!(:name => fruit_names.sample, :color => Faker::Color.name)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be able to locate versions according to their `object_changes` contents" do
|
66
|
+
expect(fruit.versions.where_object_changes(:name => name)).to eq(fruit.versions[0..1])
|
67
|
+
expect(fruit.versions.where_object_changes(:color => color)).to eq(fruit.versions[1..2])
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should be able to handle queries for multiple attributes" do
|
71
|
+
expect(fruit.versions.where_object_changes(:color => color, :name => name)).to eq([fruit.versions[1]])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Thing, :type => :model do
|
4
|
+
it { is_expected.to be_versioned }
|
5
|
+
|
6
|
+
describe "should not store object_changes", :versioning => true do
|
7
|
+
let(:thing) { Thing.create(:name =>"pencil") }
|
8
|
+
|
9
|
+
it { expect(thing.versions.last.object_changes).to be_nil }
|
10
|
+
end
|
11
|
+
end
|
data/spec/models/version_spec.rb
CHANGED
@@ -45,13 +45,60 @@ describe PaperTrail::Version, :type => :model do
|
|
45
45
|
describe "Instance" do
|
46
46
|
subject { PaperTrail::Version.new(attributes) rescue PaperTrail::Version.new }
|
47
47
|
|
48
|
+
describe '#paper_trail_originator' do
|
49
|
+
it { is_expected.to respond_to(:paper_trail_originator) }
|
50
|
+
|
51
|
+
context "No previous versions" do
|
52
|
+
specify { expect(subject.previous).to be_nil }
|
53
|
+
|
54
|
+
it "should return nil" do
|
55
|
+
expect(subject.paper_trail_originator).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "Has previous version", :versioning => true do
|
60
|
+
let(:name) { Faker::Name.name }
|
61
|
+
let(:widget) { Widget.create!(name: Faker::Name.name) }
|
62
|
+
before do
|
63
|
+
widget.versions.first.update_attributes!(:whodunnit => name)
|
64
|
+
widget.update_attributes!(name: Faker::Name.first_name)
|
65
|
+
end
|
66
|
+
subject { widget.versions.last }
|
67
|
+
|
68
|
+
specify { expect(subject.previous).to be_instance_of(PaperTrail::Version) }
|
69
|
+
|
70
|
+
it "should return nil" do
|
71
|
+
expect(subject.paper_trail_originator).to eq(name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#originator" do
|
77
|
+
it { is_expected.to respond_to(:originator) }
|
78
|
+
let(:warning_msg) do
|
79
|
+
"DEPRECATED: use `paper_trail_originator` instead of `originator`." +
|
80
|
+
" Support for `originator` will be removed in PaperTrail 4.0"
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should set the invoke `paper_trail_originator`' do
|
84
|
+
is_expected.to receive(:warn)
|
85
|
+
is_expected.to receive(:paper_trail_originator)
|
86
|
+
subject.originator
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should display a deprecation warning' do
|
90
|
+
is_expected.to receive(:warn).with(warning_msg)
|
91
|
+
subject.originator
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
48
95
|
describe '#terminator' do
|
49
96
|
it { is_expected.to respond_to(:terminator) }
|
50
97
|
|
51
98
|
let(:attributes) { {:whodunnit => Faker::Name.first_name} }
|
52
99
|
|
53
100
|
it "is an alias for the `whodunnit` attribute" do
|
54
|
-
expect(subject.
|
101
|
+
expect(subject.terminator).to eq(attributes[:whodunnit])
|
55
102
|
end
|
56
103
|
end
|
57
104
|
|
@@ -65,100 +112,128 @@ describe PaperTrail::Version, :type => :model do
|
|
65
112
|
end
|
66
113
|
|
67
114
|
describe "Class" do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
expect { PaperTrail::Version.where_object([]) }.to raise_error(ArgumentError)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context "valid arguments", :versioning => true do
|
79
|
-
let(:widget) { Widget.new }
|
80
|
-
let(:name) { Faker::Name.first_name }
|
81
|
-
let(:int) { rand(10) + 1 }
|
115
|
+
column_overrides = [false]
|
116
|
+
if ENV['DB'] == 'postgres' && ::ActiveRecord::VERSION::MAJOR >= 4
|
117
|
+
column_overrides << 'json'
|
118
|
+
# 'jsonb' column types are only supported for ActiveRecord 4.2+
|
119
|
+
column_overrides << 'jsonb' if ::ActiveRecord::VERSION::STRING >= '4.2'
|
120
|
+
end
|
82
121
|
|
122
|
+
column_overrides.shuffle.each do |override|
|
123
|
+
context "with a #{override || 'text'} column" do
|
83
124
|
before do
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
it "should be able to locate versions according to their `object` contents" do
|
93
|
-
expect(PaperTrail::Version.where_object(:name => name)).to eq([widget.versions[1]])
|
94
|
-
expect(PaperTrail::Version.where_object(:an_integer => 100)).to eq([widget.versions[2]])
|
125
|
+
if override
|
126
|
+
ActiveRecord::Base.connection.execute("SAVEPOINT pgtest;")
|
127
|
+
%w[object object_changes].each do |column|
|
128
|
+
ActiveRecord::Base.connection.execute("ALTER TABLE versions DROP COLUMN #{column};")
|
129
|
+
ActiveRecord::Base.connection.execute("ALTER TABLE versions ADD COLUMN #{column} #{override};")
|
130
|
+
end
|
131
|
+
PaperTrail::Version.reset_column_information
|
95
132
|
end
|
96
133
|
end
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
it "should be able to locate versions according to their `object` contents" do
|
103
|
-
expect(PaperTrail::Version.where_object(:name => name)).to eq([widget.versions[1]])
|
104
|
-
expect(PaperTrail::Version.where_object(:an_integer => 100)).to eq([widget.versions[2]])
|
134
|
+
after do
|
135
|
+
if override
|
136
|
+
ActiveRecord::Base.connection.execute("ROLLBACK TO SAVEPOINT pgtest;")
|
137
|
+
PaperTrail::Version.reset_column_information
|
105
138
|
end
|
106
|
-
|
107
|
-
after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
108
139
|
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe '#where_object_changes' do
|
113
|
-
it { expect(PaperTrail::Version).to respond_to(:where_object_changes) }
|
114
|
-
|
115
|
-
context "invalid arguments" do
|
116
|
-
it "should raise an error" do
|
117
|
-
expect { PaperTrail::Version.where_object_changes(:foo) }.to raise_error(ArgumentError)
|
118
|
-
expect { PaperTrail::Version.where_object_changes([]) }.to raise_error(ArgumentError)
|
119
|
-
end
|
120
|
-
end
|
121
140
|
|
122
|
-
|
123
|
-
|
124
|
-
let(:name) { Faker::Name.first_name }
|
125
|
-
let(:int) { rand(5) + 2 }
|
141
|
+
describe '#where_object' do
|
142
|
+
it { expect(PaperTrail::Version).to respond_to(:where_object) }
|
126
143
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
context "`serializer == YAML`" do
|
134
|
-
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
|
135
|
-
|
136
|
-
it "should be able to locate versions according to their `object_changes` contents" do
|
137
|
-
expect(widget.versions.where_object_changes(:name => name)).to eq(widget.versions[0..1])
|
138
|
-
expect(widget.versions.where_object_changes(:an_integer => 77)).to eq(widget.versions[1..2])
|
139
|
-
expect(widget.versions.where_object_changes(:an_integer => int)).to eq([widget.versions.last])
|
144
|
+
context "invalid arguments" do
|
145
|
+
it "should raise an error" do
|
146
|
+
expect { PaperTrail::Version.where_object(:foo) }.to raise_error(ArgumentError)
|
147
|
+
expect { PaperTrail::Version.where_object([]) }.to raise_error(ArgumentError)
|
148
|
+
end
|
140
149
|
end
|
141
150
|
|
142
|
-
|
143
|
-
|
151
|
+
context "valid arguments", :versioning => true do
|
152
|
+
let(:widget) { Widget.new }
|
153
|
+
let(:name) { Faker::Name.first_name }
|
154
|
+
let(:int) { rand(10) + 1 }
|
155
|
+
|
156
|
+
before do
|
157
|
+
widget.update_attributes!(:name => name, :an_integer => int)
|
158
|
+
widget.update_attributes!(:name => 'foobar', :an_integer => 100)
|
159
|
+
widget.update_attributes!(:name => Faker::Name.last_name, :an_integer => 15)
|
160
|
+
end
|
161
|
+
|
162
|
+
context "`serializer == YAML`" do
|
163
|
+
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
|
164
|
+
|
165
|
+
it "should be able to locate versions according to their `object` contents" do
|
166
|
+
expect(PaperTrail::Version.where_object(:name => name)).to eq([widget.versions[1]])
|
167
|
+
expect(PaperTrail::Version.where_object(:an_integer => 100)).to eq([widget.versions[2]])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "`serializer == JSON`" do
|
172
|
+
before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
|
173
|
+
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::JSON }
|
174
|
+
|
175
|
+
it "should be able to locate versions according to their `object` contents" do
|
176
|
+
expect(PaperTrail::Version.where_object(:name => name)).to eq([widget.versions[1]])
|
177
|
+
expect(PaperTrail::Version.where_object(:an_integer => 100)).to eq([widget.versions[2]])
|
178
|
+
end
|
179
|
+
|
180
|
+
after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
181
|
+
end
|
144
182
|
end
|
145
183
|
end
|
146
184
|
|
147
|
-
|
148
|
-
|
149
|
-
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::JSON }
|
185
|
+
describe '#where_object_changes' do
|
186
|
+
it { expect(PaperTrail::Version).to respond_to(:where_object_changes) }
|
150
187
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
188
|
+
context "invalid arguments" do
|
189
|
+
it "should raise an error" do
|
190
|
+
expect { PaperTrail::Version.where_object_changes(:foo) }.to raise_error(ArgumentError)
|
191
|
+
expect { PaperTrail::Version.where_object_changes([]) }.to raise_error(ArgumentError)
|
192
|
+
end
|
155
193
|
end
|
156
194
|
|
157
|
-
|
158
|
-
|
195
|
+
context "valid arguments", :versioning => true do
|
196
|
+
let(:widget) { Widget.new }
|
197
|
+
let(:name) { Faker::Name.first_name }
|
198
|
+
let(:int) { rand(5) + 2 }
|
199
|
+
|
200
|
+
before do
|
201
|
+
widget.update_attributes!(:name => name, :an_integer => 0)
|
202
|
+
widget.update_attributes!(:name => 'foobar', :an_integer => 77)
|
203
|
+
widget.update_attributes!(:name => Faker::Name.last_name, :an_integer => int)
|
204
|
+
end
|
205
|
+
|
206
|
+
context "`serializer == YAML`" do
|
207
|
+
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
|
208
|
+
|
209
|
+
it "should be able to locate versions according to their `object_changes` contents" do
|
210
|
+
expect(widget.versions.where_object_changes(:name => name)).to eq(widget.versions[0..1])
|
211
|
+
expect(widget.versions.where_object_changes(:an_integer => 77)).to eq(widget.versions[1..2])
|
212
|
+
expect(widget.versions.where_object_changes(:an_integer => int)).to eq([widget.versions.last])
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should be able to handle queries for multiple attributes" do
|
216
|
+
expect(widget.versions.where_object_changes(:an_integer => 77, :name => 'foobar')).to eq(widget.versions[1..2])
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context "`serializer == JSON`" do
|
221
|
+
before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
|
222
|
+
specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::JSON }
|
223
|
+
|
224
|
+
it "should be able to locate versions according to their `object_changes` contents" do
|
225
|
+
expect(widget.versions.where_object_changes(:name => name)).to eq(widget.versions[0..1])
|
226
|
+
expect(widget.versions.where_object_changes(:an_integer => 77)).to eq(widget.versions[1..2])
|
227
|
+
expect(widget.versions.where_object_changes(:an_integer => int)).to eq([widget.versions.last])
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should be able to handle queries for multiple attributes" do
|
231
|
+
expect(widget.versions.where_object_changes(:an_integer => 77, :name => 'foobar')).to eq(widget.versions[1..2])
|
232
|
+
end
|
233
|
+
|
234
|
+
after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
235
|
+
end
|
159
236
|
end
|
160
|
-
|
161
|
-
after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
162
237
|
end
|
163
238
|
end
|
164
239
|
end
|