paper_trail 7.1.0 → 7.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/paper_trail/record_trail.rb +1 -1
- data/lib/paper_trail/version_number.rb +1 -1
- metadata +3 -274
- data/.github/CONTRIBUTING.md +0 -151
- data/.github/ISSUE_TEMPLATE.md +0 -13
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.rubocop.yml +0 -135
- data/.rubocop_todo.yml +0 -41
- data/.travis.yml +0 -41
- data/Appraisals +0 -26
- data/CHANGELOG.md +0 -739
- data/Gemfile +0 -2
- data/MIT-LICENSE +0 -20
- data/README.md +0 -1613
- data/Rakefile +0 -38
- data/doc/bug_report_template.rb +0 -73
- data/doc/triage.md +0 -27
- data/doc/warning_about_not_setting_whodunnit.md +0 -33
- data/gemfiles/ar_4.0.gemfile +0 -7
- data/gemfiles/ar_4.2.gemfile +0 -7
- data/gemfiles/ar_5.0.gemfile +0 -8
- data/gemfiles/ar_5.1.gemfile +0 -8
- data/gemfiles/ar_master.gemfile +0 -9
- data/lib/generators/paper_trail/default_initializer.rb +0 -0
- data/paper_trail.gemspec +0 -49
- data/spec/controllers/articles_controller_spec.rb +0 -28
- data/spec/controllers/widgets_controller_spec.rb +0 -85
- data/spec/dummy_app/Rakefile +0 -7
- data/spec/dummy_app/app/controllers/application_controller.rb +0 -30
- data/spec/dummy_app/app/controllers/articles_controller.rb +0 -16
- data/spec/dummy_app/app/controllers/test_controller.rb +0 -5
- data/spec/dummy_app/app/controllers/widgets_controller.rb +0 -28
- data/spec/dummy_app/app/models/animal.rb +0 -4
- data/spec/dummy_app/app/models/article.rb +0 -25
- data/spec/dummy_app/app/models/authorship.rb +0 -5
- data/spec/dummy_app/app/models/bar_habtm.rb +0 -4
- data/spec/dummy_app/app/models/book.rb +0 -9
- data/spec/dummy_app/app/models/boolit.rb +0 -4
- data/spec/dummy_app/app/models/callback_modifier.rb +0 -45
- data/spec/dummy_app/app/models/car.rb +0 -3
- data/spec/dummy_app/app/models/cat.rb +0 -2
- data/spec/dummy_app/app/models/chapter.rb +0 -9
- data/spec/dummy_app/app/models/citation.rb +0 -5
- data/spec/dummy_app/app/models/custom_primary_key_record.rb +0 -15
- data/spec/dummy_app/app/models/customer.rb +0 -4
- data/spec/dummy_app/app/models/document.rb +0 -8
- data/spec/dummy_app/app/models/dog.rb +0 -2
- data/spec/dummy_app/app/models/editor.rb +0 -4
- data/spec/dummy_app/app/models/editorship.rb +0 -5
- data/spec/dummy_app/app/models/elephant.rb +0 -3
- data/spec/dummy_app/app/models/fluxor.rb +0 -3
- data/spec/dummy_app/app/models/foo_habtm.rb +0 -5
- data/spec/dummy_app/app/models/foo_widget.rb +0 -2
- data/spec/dummy_app/app/models/fruit.rb +0 -5
- data/spec/dummy_app/app/models/gadget.rb +0 -3
- data/spec/dummy_app/app/models/kitchen/banana.rb +0 -5
- data/spec/dummy_app/app/models/legacy_widget.rb +0 -6
- data/spec/dummy_app/app/models/line_item.rb +0 -4
- data/spec/dummy_app/app/models/not_on_update.rb +0 -4
- data/spec/dummy_app/app/models/on/create.rb +0 -6
- data/spec/dummy_app/app/models/on/destroy.rb +0 -6
- data/spec/dummy_app/app/models/on/empty_array.rb +0 -6
- data/spec/dummy_app/app/models/on/update.rb +0 -6
- data/spec/dummy_app/app/models/order.rb +0 -5
- data/spec/dummy_app/app/models/paragraph.rb +0 -5
- data/spec/dummy_app/app/models/person.rb +0 -39
- data/spec/dummy_app/app/models/post.rb +0 -3
- data/spec/dummy_app/app/models/post_with_status.rb +0 -7
- data/spec/dummy_app/app/models/quotation.rb +0 -5
- data/spec/dummy_app/app/models/section.rb +0 -6
- data/spec/dummy_app/app/models/skipper.rb +0 -3
- data/spec/dummy_app/app/models/song.rb +0 -37
- data/spec/dummy_app/app/models/thing.rb +0 -3
- data/spec/dummy_app/app/models/translation.rb +0 -11
- data/spec/dummy_app/app/models/truck.rb +0 -4
- data/spec/dummy_app/app/models/vehicle.rb +0 -4
- data/spec/dummy_app/app/models/whatchamajigger.rb +0 -4
- data/spec/dummy_app/app/models/widget.rb +0 -8
- data/spec/dummy_app/app/models/wotsit.rb +0 -8
- data/spec/dummy_app/app/versions/custom_primary_key_record_version.rb +0 -3
- data/spec/dummy_app/app/versions/joined_version.rb +0 -6
- data/spec/dummy_app/app/versions/json_version.rb +0 -3
- data/spec/dummy_app/app/versions/kitchen/banana_version.rb +0 -5
- data/spec/dummy_app/app/versions/post_version.rb +0 -3
- data/spec/dummy_app/config.ru +0 -4
- data/spec/dummy_app/config/application.rb +0 -39
- data/spec/dummy_app/config/boot.rb +0 -24
- data/spec/dummy_app/config/database.mysql.yml +0 -19
- data/spec/dummy_app/config/database.postgres.yml +0 -15
- data/spec/dummy_app/config/database.sqlite.yml +0 -15
- data/spec/dummy_app/config/environment.rb +0 -5
- data/spec/dummy_app/config/environments/development.rb +0 -36
- data/spec/dummy_app/config/environments/production.rb +0 -74
- data/spec/dummy_app/config/environments/test.rb +0 -46
- data/spec/dummy_app/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy_app/config/initializers/inflections.rb +0 -10
- data/spec/dummy_app/config/initializers/mime_types.rb +0 -5
- data/spec/dummy_app/config/initializers/paper_trail.rb +0 -1
- data/spec/dummy_app/config/initializers/secret_token.rb +0 -9
- data/spec/dummy_app/config/initializers/session_store.rb +0 -8
- data/spec/dummy_app/config/locales/en.yml +0 -5
- data/spec/dummy_app/config/routes.rb +0 -4
- data/spec/dummy_app/db/migrate/20110208155312_set_up_test_tables.rb +0 -344
- data/spec/dummy_app/db/schema.rb +0 -298
- data/spec/generators/install_generator_spec.rb +0 -88
- data/spec/models/animal_spec.rb +0 -61
- data/spec/models/article_spec.rb +0 -186
- data/spec/models/boolit_spec.rb +0 -41
- data/spec/models/callback_modifier_spec.rb +0 -92
- data/spec/models/car_spec.rb +0 -13
- data/spec/models/custom_primary_key_record_spec.rb +0 -18
- data/spec/models/document_spec.rb +0 -57
- data/spec/models/gadget_spec.rb +0 -63
- data/spec/models/joined_version_spec.rb +0 -41
- data/spec/models/json_version_spec.rb +0 -101
- data/spec/models/kitchen/banana_spec.rb +0 -14
- data/spec/models/legacy_widget_spec.rb +0 -40
- data/spec/models/not_on_update_spec.rb +0 -22
- data/spec/models/on/create_spec.rb +0 -27
- data/spec/models/on/destroy_spec.rb +0 -27
- data/spec/models/on/empty_array_spec.rb +0 -30
- data/spec/models/on/update_spec.rb +0 -27
- data/spec/models/post_with_status_spec.rb +0 -46
- data/spec/models/skipper_spec.rb +0 -42
- data/spec/models/thing_spec.rb +0 -11
- data/spec/models/translation_spec.rb +0 -70
- data/spec/models/vehicle_spec.rb +0 -5
- data/spec/models/version_spec.rb +0 -282
- data/spec/models/widget_spec.rb +0 -338
- data/spec/modules/paper_trail_spec.rb +0 -27
- data/spec/modules/version_concern_spec.rb +0 -28
- data/spec/modules/version_number_spec.rb +0 -18
- data/spec/paper_trail/associations_spec.rb +0 -965
- data/spec/paper_trail/cleaner_spec.rb +0 -152
- data/spec/paper_trail/config_spec.rb +0 -45
- data/spec/paper_trail/model_spec.rb +0 -992
- data/spec/paper_trail/serializer_spec.rb +0 -85
- data/spec/paper_trail/serializers/custom_json_serializer_spec.rb +0 -18
- data/spec/paper_trail/serializers/custom_yaml_serializer_spec.rb +0 -45
- data/spec/paper_trail/serializers/json_spec.rb +0 -57
- data/spec/paper_trail/serializers/yaml_spec.rb +0 -42
- data/spec/paper_trail/thread_safety_spec.rb +0 -44
- data/spec/paper_trail/version_limit_spec.rb +0 -55
- data/spec/paper_trail/version_spec.rb +0 -96
- data/spec/paper_trail_spec.rb +0 -122
- data/spec/requests/articles_spec.rb +0 -34
- data/spec/spec_helper.rb +0 -78
- data/spec/support/alt_db_init.rb +0 -54
- data/spec/support/custom_json_serializer.rb +0 -13
@@ -1,85 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "support/custom_json_serializer"
|
3
|
-
|
4
|
-
RSpec.describe(PaperTrail, versioning: true) do
|
5
|
-
context "YAML serializer" do
|
6
|
-
it "saves the expected YAML in the object column" do
|
7
|
-
customer = Customer.create(name: "Some text.")
|
8
|
-
original_attributes = customer.paper_trail.attributes_before_change
|
9
|
-
customer.update(name: "Some more text.")
|
10
|
-
expect(customer.versions.length).to(eq(2))
|
11
|
-
expect(customer.versions[0].reify).to(be_nil)
|
12
|
-
expect(customer.versions[1].reify.name).to(eq("Some text."))
|
13
|
-
expect(YAML.load(customer.versions[1].object)).to(eq(original_attributes))
|
14
|
-
expect(customer.versions[1].object).to(eq(YAML.dump(original_attributes)))
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
context "JSON Serializer" do
|
19
|
-
before do
|
20
|
-
PaperTrail.configure do |config|
|
21
|
-
config.serializer = PaperTrail::Serializers::JSON
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
after do
|
26
|
-
PaperTrail.config.serializer = PaperTrail::Serializers::YAML
|
27
|
-
end
|
28
|
-
|
29
|
-
it "reify with JSON serializer" do
|
30
|
-
customer = Customer.create(name: "Some text.")
|
31
|
-
original_attributes = customer.paper_trail.attributes_before_change
|
32
|
-
customer.update(name: "Some more text.")
|
33
|
-
expect(customer.versions.length).to(eq(2))
|
34
|
-
expect(customer.versions[0].reify).to(be_nil)
|
35
|
-
expect(customer.versions[1].reify.name).to(eq("Some text."))
|
36
|
-
expect(ActiveSupport::JSON.decode(customer.versions[1].object)).to(eq(original_attributes))
|
37
|
-
expect(customer.versions[1].object).to(eq(ActiveSupport::JSON.encode(original_attributes)))
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "#changeset" do
|
41
|
-
it "returns the expected hash" do
|
42
|
-
customer = Customer.create(name: "Some text.")
|
43
|
-
customer.update(name: "Some more text.")
|
44
|
-
initial_changeset = { "name" => [nil, "Some text."], "id" => [nil, customer.id] }
|
45
|
-
second_changeset = { "name" => ["Some text.", "Some more text."] }
|
46
|
-
expect(customer.versions[0].changeset).to(eq(initial_changeset))
|
47
|
-
expect(customer.versions[1].changeset).to(eq(second_changeset))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "Custom Serializer" do
|
53
|
-
before do
|
54
|
-
PaperTrail.configure { |config| config.serializer = CustomJsonSerializer }
|
55
|
-
end
|
56
|
-
|
57
|
-
after do
|
58
|
-
PaperTrail.config.serializer = PaperTrail::Serializers::YAML
|
59
|
-
end
|
60
|
-
|
61
|
-
it "reify with custom serializer" do
|
62
|
-
customer = Customer.create
|
63
|
-
original_attributes = customer.paper_trail.attributes_before_change.reject { |_k, v| v.nil? }
|
64
|
-
customer.update(name: "Some more text.")
|
65
|
-
expect(customer.versions.length).to(eq(2))
|
66
|
-
expect(customer.versions[0].reify).to(be_nil)
|
67
|
-
expect(customer.versions[1].reify.name).to(be_nil)
|
68
|
-
expect(
|
69
|
-
ActiveSupport::JSON.decode(customer.versions[1].object)
|
70
|
-
).to eq(original_attributes)
|
71
|
-
expect(
|
72
|
-
customer.versions[1].object
|
73
|
-
).to eq(ActiveSupport::JSON.encode(original_attributes))
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "#changeset" do
|
77
|
-
it "store object_changes" do
|
78
|
-
customer = Customer.create
|
79
|
-
customer.update(name: "banana")
|
80
|
-
expect(customer.versions[0].changeset).to eq("id" => [nil, customer.id])
|
81
|
-
expect(customer.versions[1].changeset).to eq("name" => [nil, "banana"])
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require_relative "../../support/custom_json_serializer"
|
3
|
-
|
4
|
-
RSpec.describe CustomJsonSerializer do
|
5
|
-
describe ".load" do
|
6
|
-
it "deserializes, removing pairs with blank keys or values" do
|
7
|
-
hash = { "key1" => "banana", "tkey" => nil, "" => "foo" }
|
8
|
-
expect(described_class.load(hash.to_json)).to(eq("key1" => "banana"))
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
describe ".dump" do
|
13
|
-
it "serializes to JSON, removing pairs with nil values" do
|
14
|
-
hash = { "key1" => "banana", "tkey" => nil, "" => "foo" }
|
15
|
-
expect(described_class.dump(hash)).to(eq('{"key1":"banana","":"foo"}'))
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module CustomYamlSerializer
|
4
|
-
extend PaperTrail::Serializers::YAML
|
5
|
-
|
6
|
-
def self.load(string)
|
7
|
-
parsed_value = super(string)
|
8
|
-
if parsed_value.is_a?(Hash)
|
9
|
-
parsed_value.reject { |k, v| (k.blank? || v.blank?) }
|
10
|
-
else
|
11
|
-
parsed_value
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.dump(object)
|
16
|
-
object.is_a?(Hash) ? super(object.reject { |_k, v| v.nil? }) : super
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
RSpec.describe CustomYamlSerializer do
|
21
|
-
let(:word_hash) {
|
22
|
-
{
|
23
|
-
"key1" => ::FFaker::Lorem.word,
|
24
|
-
"key2" => nil,
|
25
|
-
"tkey" => nil,
|
26
|
-
"" => "foo"
|
27
|
-
}
|
28
|
-
}
|
29
|
-
|
30
|
-
context(".load") do
|
31
|
-
it("deserializes YAML to Ruby, removing pairs with blank keys or values") do
|
32
|
-
expect(described_class.load(word_hash.to_yaml)).to eq(
|
33
|
-
word_hash.reject { |k, v| (k.blank? || v.blank?) }
|
34
|
-
)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
context(".dump") do
|
39
|
-
it("serializes Ruby to YAML, removing pairs with nil values") do
|
40
|
-
expect(described_class.dump(word_hash)).to eq(
|
41
|
-
word_hash.reject { |_k, v| v.nil? }.to_yaml
|
42
|
-
)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module PaperTrail
|
4
|
-
module Serializers
|
5
|
-
::RSpec.describe JSON do
|
6
|
-
let(:word_hash) {
|
7
|
-
(1..4).each_with_object({}) { |i, a| a["key#{i}"] = ::FFaker::Lorem.word }
|
8
|
-
}
|
9
|
-
let(:word_array) { [].fill(0, rand(5) + 4) { ::FFaker::Lorem.word } }
|
10
|
-
|
11
|
-
describe ".load" do
|
12
|
-
it "deserialize JSON to Ruby" do
|
13
|
-
expect(described_class.load(word_hash.to_json)).to eq(word_hash)
|
14
|
-
expect(described_class.load(word_array.to_json)).to eq(word_array)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe ".dump" do
|
19
|
-
it "serializes Ruby to JSON" do
|
20
|
-
expect(described_class.dump(word_hash)).to eq(word_hash.to_json)
|
21
|
-
expect(described_class.dump(word_array)).to eq(word_array.to_json)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe ".where_object_condition" do
|
26
|
-
context "when value is a string" do
|
27
|
-
it "construct correct WHERE query" do
|
28
|
-
matches = described_class.
|
29
|
-
where_object_condition(PaperTrail::Version.arel_table[:object], :arg1, "Val 1")
|
30
|
-
expect(matches.instance_of?(Arel::Nodes::Matches)).to(eq(true))
|
31
|
-
expect(matches.right.val).to eq("%\"arg1\":\"Val 1\"%")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "when value is null" do
|
36
|
-
it "construct correct WHERE query" do
|
37
|
-
matches = described_class.
|
38
|
-
where_object_condition(PaperTrail::Version.arel_table[:object], :arg1, nil)
|
39
|
-
expect(matches.instance_of?(Arel::Nodes::Matches)).to(eq(true))
|
40
|
-
expect(matches.right.val).to(eq("%\"arg1\":null%"))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context "when value is a number" do
|
45
|
-
it "construct correct WHERE query" do
|
46
|
-
grouping = described_class.
|
47
|
-
where_object_condition(PaperTrail::Version.arel_table[:object], :arg1, -3.5)
|
48
|
-
expect(grouping.instance_of?(Arel::Nodes::Grouping)).to(eq(true))
|
49
|
-
matches = grouping.select { |v| v.instance_of?(Arel::Nodes::Matches) }
|
50
|
-
expect(matches.first.right.val).to eq("%\"arg1\":-3.5,%")
|
51
|
-
expect(matches.last.right.val).to eq("%\"arg1\":-3.5}%")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module PaperTrail
|
4
|
-
module Serializers
|
5
|
-
::RSpec.describe(YAML, versioning: true) do
|
6
|
-
let(:array) { ::Array.new(10) { ::FFaker::Lorem.word } }
|
7
|
-
let(:hash) {
|
8
|
-
{
|
9
|
-
alice: "bob",
|
10
|
-
binary: 0xdeadbeef,
|
11
|
-
octal_james_bond: 0o7,
|
12
|
-
int: 42,
|
13
|
-
float: 4.2
|
14
|
-
}
|
15
|
-
}
|
16
|
-
|
17
|
-
describe ".load" do
|
18
|
-
it "deserializes YAML to Ruby" do
|
19
|
-
expect(described_class.load(hash.to_yaml)).to eq(hash)
|
20
|
-
expect(described_class.load(array.to_yaml)).to eq(array)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe ".dump" do
|
25
|
-
it "serializes Ruby to YAML" do
|
26
|
-
expect(described_class.dump(hash)).to eq(hash.to_yaml)
|
27
|
-
expect(described_class.dump(array)).to eq(array.to_yaml)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe ".where_object" do
|
32
|
-
it "constructs the correct WHERE query" do
|
33
|
-
matches = described_class.where_object_condition(
|
34
|
-
::PaperTrail::Version.arel_table[:object], :arg1, "Val 1"
|
35
|
-
)
|
36
|
-
expect(matches.instance_of?(Arel::Nodes::Matches)).to(eq(true))
|
37
|
-
expect(matches.right.val).to eq("%\narg1: Val 1\n%")
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
RSpec.describe PaperTrail do
|
4
|
-
describe "#set_paper_trail_whodunnit" do
|
5
|
-
it "is thread-safe" do
|
6
|
-
blocked = true
|
7
|
-
slow_thread = Thread.new do
|
8
|
-
controller = TestController.new
|
9
|
-
controller.send(:set_paper_trail_whodunnit)
|
10
|
-
sleep(0.001) while blocked
|
11
|
-
described_class.whodunnit
|
12
|
-
end
|
13
|
-
fast_thread = Thread.new do
|
14
|
-
controller = TestController.new
|
15
|
-
controller.send(:set_paper_trail_whodunnit)
|
16
|
-
who = described_class.whodunnit
|
17
|
-
blocked = false
|
18
|
-
who
|
19
|
-
end
|
20
|
-
expect(fast_thread.value).not_to(eq(slow_thread.value))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "#without_versioning" do
|
25
|
-
it "is thread-safe" do
|
26
|
-
enabled = nil
|
27
|
-
slow_thread = Thread.new do
|
28
|
-
Widget.new.paper_trail.without_versioning do
|
29
|
-
sleep(0.01)
|
30
|
-
enabled = Widget.paper_trail.enabled?
|
31
|
-
sleep(0.01)
|
32
|
-
end
|
33
|
-
enabled
|
34
|
-
end
|
35
|
-
fast_thread = Thread.new do
|
36
|
-
sleep(0.005)
|
37
|
-
Widget.paper_trail.enabled?
|
38
|
-
end
|
39
|
-
expect(fast_thread.value).not_to(eq(slow_thread.value))
|
40
|
-
expect(Widget.paper_trail.enabled?).to(eq(true))
|
41
|
-
expect(described_class.enabled_for_model?(Widget)).to(eq(true))
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module PaperTrail
|
4
|
-
::RSpec.describe Cleaner, versioning: true do
|
5
|
-
after do
|
6
|
-
PaperTrail.config.version_limit = nil
|
7
|
-
end
|
8
|
-
|
9
|
-
it "cleans up old versions" do
|
10
|
-
PaperTrail.config.version_limit = 10
|
11
|
-
widget = Widget.create
|
12
|
-
|
13
|
-
100.times do |i|
|
14
|
-
widget.update_attributes(name: "Name #{i}")
|
15
|
-
expect(Widget.find(widget.id).versions.count).to be <= 11
|
16
|
-
# 11 versions = 10 updates + 1 create.
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
it "deletes oldest versions, when the database returns them in a different order" do
|
21
|
-
epoch = DateTime.new(2017, 1, 1)
|
22
|
-
|
23
|
-
widget = Timecop.freeze(epoch) { Widget.create }
|
24
|
-
|
25
|
-
# Sometimes a database will returns records in a different order than
|
26
|
-
# they were inserted. That's hard to get the database to do, so we'll
|
27
|
-
# just create them out-of-order:
|
28
|
-
(1..5).to_a.shuffle.each do |n|
|
29
|
-
Timecop.freeze(epoch + n.hours) do
|
30
|
-
PaperTrail::Version.create!(
|
31
|
-
item: widget,
|
32
|
-
event: "update",
|
33
|
-
object: { "id" => widget.id, "name" => "Name #{n}" }.to_yaml
|
34
|
-
)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
expect(Widget.find(widget.id).versions.count).to eq(6) # 1 create + 5 updates
|
38
|
-
|
39
|
-
# Now, we've recreated the scenario where we can accidentally clean up
|
40
|
-
# the wrong versions. Re-enable the version_limit, and trigger the
|
41
|
-
# clean-up:
|
42
|
-
PaperTrail.config.version_limit = 3
|
43
|
-
widget.versions.last.send(:enforce_version_limit!)
|
44
|
-
|
45
|
-
# Verify that we have fewer versions:
|
46
|
-
expect(widget.reload.versions.count).to eq(4) # 1 create + 4 updates
|
47
|
-
|
48
|
-
# Exclude the create, because the create will return nil for `#reify`.
|
49
|
-
last_names = widget.versions.not_creates.map(&:reify).map(&:name)
|
50
|
-
expect(last_names).to eq(["Name 3", "Name 4", "Name 5"])
|
51
|
-
# No matter what order the version records are returned it, we should
|
52
|
-
# always keep the most-recent changes.
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module PaperTrail
|
4
|
-
::RSpec.describe(Version, versioning: true) do
|
5
|
-
describe ".creates" do
|
6
|
-
it "returns only create events" do
|
7
|
-
animal = Animal.create(name: "Foo")
|
8
|
-
animal.update_attributes(name: "Bar")
|
9
|
-
expect(described_class.creates.pluck(:event)).to eq(["create"])
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
describe ".updates" do
|
14
|
-
it "returns only update events" do
|
15
|
-
animal = Animal.create
|
16
|
-
animal.update_attributes(name: "Animal")
|
17
|
-
expect(described_class.updates.pluck(:event)).to eq(["update"])
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe ".destroys" do
|
22
|
-
it "returns only destroy events" do
|
23
|
-
animal = Animal.create
|
24
|
-
animal.destroy
|
25
|
-
expect(described_class.destroys.pluck(:event)).to eq(["destroy"])
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe ".not_creates" do
|
30
|
-
it "returns all versions except create events" do
|
31
|
-
animal = Animal.create
|
32
|
-
animal.update_attributes(name: "Animal")
|
33
|
-
animal.destroy
|
34
|
-
expect(
|
35
|
-
described_class.not_creates.pluck(:event)
|
36
|
-
).to match_array(%w[update destroy])
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe ".subsequent" do
|
41
|
-
context "given a timestamp" do
|
42
|
-
it "returns all versions that were created after the timestamp" do
|
43
|
-
animal = Animal.create
|
44
|
-
2.times do
|
45
|
-
animal.update_attributes(name: FFaker::Lorem.word)
|
46
|
-
end
|
47
|
-
value = described_class.subsequent(1.hour.ago, true)
|
48
|
-
expect(value).to eq(animal.versions.to_a)
|
49
|
-
expect(value.to_sql).to match(
|
50
|
-
/ORDER BY #{described_class.arel_table[:created_at].asc.to_sql}/
|
51
|
-
)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context "given a Version" do
|
56
|
-
it "grab the timestamp from the version and use that as the value" do
|
57
|
-
animal = Animal.create
|
58
|
-
2.times do
|
59
|
-
animal.update_attributes(name: FFaker::Lorem.word)
|
60
|
-
end
|
61
|
-
expect(described_class.subsequent(animal.versions.first)).to eq(
|
62
|
-
animal.versions.to_a.drop(1)
|
63
|
-
)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
describe ".preceding" do
|
69
|
-
context "given a timestamp" do
|
70
|
-
it "returns all versions that were created before the timestamp" do
|
71
|
-
animal = Animal.create
|
72
|
-
2.times do
|
73
|
-
animal.update_attributes(name: FFaker::Lorem.word)
|
74
|
-
end
|
75
|
-
value = described_class.preceding(5.seconds.from_now, true)
|
76
|
-
expect(value).to eq(animal.versions.reverse)
|
77
|
-
expect(value.to_sql).to match(
|
78
|
-
/ORDER BY #{described_class.arel_table[:created_at].desc.to_sql}/
|
79
|
-
)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context "given a Version" do
|
84
|
-
it "grab the timestamp from the version and use that as the value" do
|
85
|
-
animal = Animal.create
|
86
|
-
2.times do
|
87
|
-
animal.update_attributes(name: FFaker::Lorem.word)
|
88
|
-
end
|
89
|
-
expect(described_class.preceding(animal.versions.last)).to eq(
|
90
|
-
animal.versions.to_a.tap(&:pop).reverse
|
91
|
-
)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|