paper_trail 5.2.3 → 11.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 +5 -5
- data/lib/generators/paper_trail/install/USAGE +3 -0
- data/lib/generators/paper_trail/install/install_generator.rb +75 -0
- data/lib/generators/paper_trail/{templates/add_object_changes_to_versions.rb → install/templates/add_object_changes_to_versions.rb.erb} +1 -1
- data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +36 -0
- data/lib/generators/paper_trail/migration_generator.rb +38 -0
- data/lib/generators/paper_trail/update_item_subtype/USAGE +4 -0
- data/lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb +85 -0
- data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +17 -0
- data/lib/paper_trail.rb +82 -130
- data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +27 -0
- data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +15 -44
- data/lib/paper_trail/attribute_serializers/object_attribute.rb +2 -0
- data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +2 -0
- data/lib/paper_trail/cleaner.rb +3 -1
- data/lib/paper_trail/compatibility.rb +51 -0
- data/lib/paper_trail/config.rb +11 -49
- data/lib/paper_trail/events/base.rb +323 -0
- data/lib/paper_trail/events/create.rb +32 -0
- data/lib/paper_trail/events/destroy.rb +42 -0
- data/lib/paper_trail/events/update.rb +60 -0
- data/lib/paper_trail/frameworks/active_record.rb +2 -1
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +8 -3
- data/lib/paper_trail/frameworks/cucumber.rb +5 -3
- data/lib/paper_trail/frameworks/rails.rb +2 -0
- data/lib/paper_trail/frameworks/rails/controller.rb +33 -43
- data/lib/paper_trail/frameworks/rails/engine.rb +34 -1
- data/lib/paper_trail/frameworks/rspec.rb +17 -4
- data/lib/paper_trail/frameworks/rspec/helpers.rb +2 -0
- data/lib/paper_trail/has_paper_trail.rb +22 -310
- data/lib/paper_trail/model_config.rb +157 -109
- data/lib/paper_trail/queries/versions/where_object.rb +65 -0
- data/lib/paper_trail/queries/versions/where_object_changes.rb +75 -0
- data/lib/paper_trail/record_history.rb +3 -9
- data/lib/paper_trail/record_trail.rb +169 -319
- data/lib/paper_trail/reifier.rb +53 -374
- data/lib/paper_trail/request.rb +166 -0
- data/lib/paper_trail/serializers/json.rb +9 -10
- data/lib/paper_trail/serializers/yaml.rb +15 -28
- data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +48 -0
- data/lib/paper_trail/version_concern.rb +160 -155
- data/lib/paper_trail/version_number.rb +12 -4
- metadata +77 -372
- data/.github/CONTRIBUTING.md +0 -109
- data/.github/ISSUE_TEMPLATE.md +0 -13
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.rubocop.yml +0 -99
- data/.rubocop_todo.yml +0 -22
- data/.travis.yml +0 -41
- data/Appraisals +0 -38
- data/CHANGELOG.md +0 -560
- data/Gemfile +0 -2
- data/MIT-LICENSE +0 -20
- data/README.md +0 -1654
- data/Rakefile +0 -30
- data/doc/bug_report_template.rb +0 -69
- data/doc/warning_about_not_setting_whodunnit.md +0 -32
- data/gemfiles/ar3.gemfile +0 -19
- data/gemfiles/ar4.gemfile +0 -8
- data/gemfiles/ar5.gemfile +0 -9
- data/lib/generators/paper_trail/USAGE +0 -2
- data/lib/generators/paper_trail/default_initializer.rb +0 -0
- data/lib/generators/paper_trail/install_generator.rb +0 -57
- data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +0 -13
- data/lib/generators/paper_trail/templates/create_version_associations.rb +0 -22
- data/lib/generators/paper_trail/templates/create_versions.rb +0 -80
- data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +0 -48
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +0 -11
- data/lib/paper_trail/frameworks/sinatra.rb +0 -40
- data/lib/paper_trail/version_association_concern.rb +0 -17
- data/paper_trail.gemspec +0 -56
- data/spec/generators/install_generator_spec.rb +0 -66
- data/spec/generators/paper_trail/templates/create_versions_spec.rb +0 -51
- data/spec/models/animal_spec.rb +0 -36
- data/spec/models/boolit_spec.rb +0 -48
- data/spec/models/callback_modifier_spec.rb +0 -96
- data/spec/models/car_spec.rb +0 -13
- data/spec/models/custom_primary_key_record_spec.rb +0 -18
- data/spec/models/fluxor_spec.rb +0 -17
- data/spec/models/gadget_spec.rb +0 -68
- data/spec/models/joined_version_spec.rb +0 -47
- data/spec/models/json_version_spec.rb +0 -102
- data/spec/models/kitchen/banana_spec.rb +0 -14
- data/spec/models/not_on_update_spec.rb +0 -22
- data/spec/models/post_with_status_spec.rb +0 -50
- data/spec/models/skipper_spec.rb +0 -46
- data/spec/models/thing_spec.rb +0 -11
- data/spec/models/truck_spec.rb +0 -5
- data/spec/models/vehicle_spec.rb +0 -5
- data/spec/models/version_spec.rb +0 -272
- data/spec/models/widget_spec.rb +0 -343
- data/spec/modules/paper_trail_spec.rb +0 -27
- data/spec/modules/version_concern_spec.rb +0 -31
- data/spec/modules/version_number_spec.rb +0 -43
- data/spec/paper_trail/config_spec.rb +0 -33
- data/spec/paper_trail_spec.rb +0 -79
- data/spec/rails_helper.rb +0 -34
- data/spec/requests/articles_spec.rb +0 -34
- data/spec/spec_helper.rb +0 -114
- data/spec/support/alt_db_init.rb +0 -54
- data/test/custom_json_serializer.rb +0 -13
- data/test/dummy/Rakefile +0 -7
- data/test/dummy/app/controllers/application_controller.rb +0 -33
- data/test/dummy/app/controllers/articles_controller.rb +0 -20
- data/test/dummy/app/controllers/test_controller.rb +0 -5
- data/test/dummy/app/controllers/widgets_controller.rb +0 -32
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/models/animal.rb +0 -6
- data/test/dummy/app/models/article.rb +0 -24
- data/test/dummy/app/models/authorship.rb +0 -5
- data/test/dummy/app/models/bar_habtm.rb +0 -4
- data/test/dummy/app/models/book.rb +0 -9
- data/test/dummy/app/models/boolit.rb +0 -4
- data/test/dummy/app/models/callback_modifier.rb +0 -45
- data/test/dummy/app/models/car.rb +0 -3
- data/test/dummy/app/models/cat.rb +0 -2
- data/test/dummy/app/models/chapter.rb +0 -9
- data/test/dummy/app/models/citation.rb +0 -5
- data/test/dummy/app/models/custom_primary_key_record.rb +0 -13
- data/test/dummy/app/models/customer.rb +0 -4
- data/test/dummy/app/models/document.rb +0 -4
- data/test/dummy/app/models/dog.rb +0 -2
- data/test/dummy/app/models/editor.rb +0 -4
- data/test/dummy/app/models/editorship.rb +0 -5
- data/test/dummy/app/models/elephant.rb +0 -3
- data/test/dummy/app/models/fluxor.rb +0 -3
- data/test/dummy/app/models/foo_habtm.rb +0 -5
- data/test/dummy/app/models/foo_widget.rb +0 -2
- data/test/dummy/app/models/fruit.rb +0 -5
- data/test/dummy/app/models/gadget.rb +0 -3
- data/test/dummy/app/models/kitchen/banana.rb +0 -5
- data/test/dummy/app/models/legacy_widget.rb +0 -4
- data/test/dummy/app/models/line_item.rb +0 -4
- data/test/dummy/app/models/not_on_update.rb +0 -4
- data/test/dummy/app/models/order.rb +0 -5
- data/test/dummy/app/models/paragraph.rb +0 -5
- data/test/dummy/app/models/person.rb +0 -38
- data/test/dummy/app/models/post.rb +0 -3
- data/test/dummy/app/models/post_with_status.rb +0 -8
- data/test/dummy/app/models/protected_widget.rb +0 -3
- data/test/dummy/app/models/quotation.rb +0 -5
- data/test/dummy/app/models/section.rb +0 -6
- data/test/dummy/app/models/skipper.rb +0 -6
- data/test/dummy/app/models/song.rb +0 -41
- data/test/dummy/app/models/thing.rb +0 -3
- data/test/dummy/app/models/translation.rb +0 -4
- data/test/dummy/app/models/truck.rb +0 -4
- data/test/dummy/app/models/vehicle.rb +0 -4
- data/test/dummy/app/models/whatchamajigger.rb +0 -4
- data/test/dummy/app/models/widget.rb +0 -16
- data/test/dummy/app/models/wotsit.rb +0 -8
- data/test/dummy/app/versions/custom_primary_key_record_version.rb +0 -3
- data/test/dummy/app/versions/joined_version.rb +0 -6
- data/test/dummy/app/versions/json_version.rb +0 -3
- data/test/dummy/app/versions/kitchen/banana_version.rb +0 -5
- data/test/dummy/app/versions/post_version.rb +0 -3
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/config.ru +0 -4
- data/test/dummy/config/application.rb +0 -80
- data/test/dummy/config/boot.rb +0 -10
- data/test/dummy/config/database.mysql.yml +0 -19
- data/test/dummy/config/database.postgres.yml +0 -15
- data/test/dummy/config/database.sqlite.yml +0 -15
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -41
- data/test/dummy/config/environments/production.rb +0 -74
- data/test/dummy/config/environments/test.rb +0 -51
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/test/dummy/config/initializers/inflections.rb +0 -10
- data/test/dummy/config/initializers/mime_types.rb +0 -5
- data/test/dummy/config/initializers/paper_trail.rb +0 -9
- data/test/dummy/config/initializers/secret_token.rb +0 -9
- data/test/dummy/config/initializers/session_store.rb +0 -8
- data/test/dummy/config/locales/en.yml +0 -5
- data/test/dummy/config/routes.rb +0 -4
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +0 -361
- data/test/dummy/db/schema.rb +0 -288
- data/test/dummy/script/rails +0 -8
- data/test/functional/controller_test.rb +0 -90
- data/test/functional/enabled_for_controller_test.rb +0 -28
- data/test/functional/modular_sinatra_test.rb +0 -46
- data/test/functional/sinatra_test.rb +0 -51
- data/test/functional/thread_safety_test.rb +0 -46
- data/test/test_helper.rb +0 -127
- data/test/time_travel_helper.rb +0 -1
- data/test/unit/associations_test.rb +0 -1016
- data/test/unit/cleaner_test.rb +0 -188
- data/test/unit/inheritance_column_test.rb +0 -43
- data/test/unit/model_test.rb +0 -1489
- data/test/unit/protected_attrs_test.rb +0 -52
- data/test/unit/serializer_test.rb +0 -119
- data/test/unit/serializers/json_test.rb +0 -95
- data/test/unit/serializers/mixin_json_test.rb +0 -37
- data/test/unit/serializers/mixin_yaml_test.rb +0 -53
- data/test/unit/serializers/yaml_test.rb +0 -54
- data/test/unit/timestamp_test.rb +0 -41
- data/test/unit/version_test.rb +0 -119
@@ -1,51 +0,0 @@
|
|
1
|
-
# PaperTrail is not compatible with sinatra 2 yet. Contributions welcome.
|
2
|
-
if Gem::Version.new(Rack.release) < Gem::Version.new("2.0.0.alpha")
|
3
|
-
require "test_helper"
|
4
|
-
# require 'sinatra/main'
|
5
|
-
|
6
|
-
# --- Tests for non-modular `Sinatra::Application` style ----
|
7
|
-
module Sinatra
|
8
|
-
class Application
|
9
|
-
configs = YAML.load_file(File.expand_path("../../dummy/config/database.yml", __FILE__))
|
10
|
-
ActiveRecord::Base.configurations = configs
|
11
|
-
ActiveRecord::Base.establish_connection(:test)
|
12
|
-
|
13
|
-
# We shouldn't actually need this line if I'm not mistaken but the tests
|
14
|
-
# seem to fail without it ATM
|
15
|
-
register PaperTrail::Sinatra
|
16
|
-
|
17
|
-
get "/test" do
|
18
|
-
Widget.create!(name: "bar")
|
19
|
-
"Hai"
|
20
|
-
end
|
21
|
-
|
22
|
-
def current_user
|
23
|
-
@current_user ||= OpenStruct.new(id: "raboof")
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class SinatraTest < ActionDispatch::IntegrationTest
|
29
|
-
include Rack::Test::Methods
|
30
|
-
|
31
|
-
def app
|
32
|
-
@app ||= Sinatra::Application
|
33
|
-
end
|
34
|
-
|
35
|
-
test "baseline" do
|
36
|
-
assert_nil Widget.create.versions.first.whodunnit
|
37
|
-
end
|
38
|
-
|
39
|
-
context "`PaperTrail::Sinatra` in a `Sinatra::Application` application" do
|
40
|
-
should "sets the `user_for_paper_trail` from the `current_user` method" do
|
41
|
-
get "/test"
|
42
|
-
assert_equal "Hai", last_response.body
|
43
|
-
widget = Widget.last
|
44
|
-
assert_not_nil widget
|
45
|
-
assert_equal "bar", widget.name
|
46
|
-
assert_equal 1, widget.versions.size
|
47
|
-
assert_equal "raboof", widget.versions.first.whodunnit
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class ThreadSafetyTest < ActionController::TestCase
|
4
|
-
test "thread-safe when using #set_paper_trail_whodunnit" do
|
5
|
-
blocked = true
|
6
|
-
|
7
|
-
slow_thread = Thread.new do
|
8
|
-
controller = TestController.new
|
9
|
-
controller.send :set_paper_trail_whodunnit
|
10
|
-
sleep 0.001 while blocked
|
11
|
-
PaperTrail.whodunnit
|
12
|
-
end
|
13
|
-
|
14
|
-
fast_thread = Thread.new do
|
15
|
-
controller = TestController.new
|
16
|
-
controller.send :set_paper_trail_whodunnit
|
17
|
-
who = PaperTrail.whodunnit
|
18
|
-
blocked = false
|
19
|
-
who
|
20
|
-
end
|
21
|
-
|
22
|
-
assert_not_equal slow_thread.value, fast_thread.value
|
23
|
-
end
|
24
|
-
|
25
|
-
test "thread-safe when using #without_versioning" do
|
26
|
-
enabled = nil
|
27
|
-
|
28
|
-
slow_thread = Thread.new do
|
29
|
-
Widget.new.paper_trail.without_versioning do
|
30
|
-
sleep(0.01)
|
31
|
-
enabled = Widget.paper_trail.enabled?
|
32
|
-
sleep(0.01)
|
33
|
-
end
|
34
|
-
enabled
|
35
|
-
end
|
36
|
-
|
37
|
-
fast_thread = Thread.new do
|
38
|
-
sleep(0.005)
|
39
|
-
Widget.paper_trail.enabled?
|
40
|
-
end
|
41
|
-
|
42
|
-
assert_not_equal slow_thread.value, fast_thread.value
|
43
|
-
assert Widget.paper_trail.enabled?
|
44
|
-
assert PaperTrail.enabled_for_model?(Widget)
|
45
|
-
end
|
46
|
-
end
|
data/test/test_helper.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
require "pry-nav"
|
2
|
-
|
3
|
-
ENV["RAILS_ENV"] = "test"
|
4
|
-
ENV["DB"] ||= "sqlite"
|
5
|
-
|
6
|
-
unless File.exist?(File.expand_path("../../test/dummy/config/database.yml", __FILE__))
|
7
|
-
warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
|
8
|
-
end
|
9
|
-
|
10
|
-
def using_mysql?
|
11
|
-
@using_mysql ||= ActiveRecord::Base.connection_config[:adapter].to_sym == :mysql2
|
12
|
-
end
|
13
|
-
|
14
|
-
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
15
|
-
require "rails/test_help"
|
16
|
-
require "shoulda"
|
17
|
-
require "ffaker"
|
18
|
-
require "database_cleaner"
|
19
|
-
|
20
|
-
def active_record_gem_version
|
21
|
-
Gem::Version.new(ActiveRecord::VERSION::STRING)
|
22
|
-
end
|
23
|
-
|
24
|
-
if active_record_gem_version >= Gem::Version.new("5.0.0.beta1")
|
25
|
-
# See https://github.com/rails/rails-controller-testing/issues/5
|
26
|
-
ActionController::TestCase.send(:include, Rails::Controller::Testing::TestProcess)
|
27
|
-
end
|
28
|
-
|
29
|
-
Rails.backtrace_cleaner.remove_silencers!
|
30
|
-
|
31
|
-
# Run any available migration
|
32
|
-
ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
|
33
|
-
|
34
|
-
# Load support files
|
35
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
36
|
-
|
37
|
-
# DatabaseCleaner is apparently necessary for doing proper transactions within MySQL (ugh)
|
38
|
-
DatabaseCleaner.strategy = :truncation
|
39
|
-
|
40
|
-
# global setup block resetting Thread.current
|
41
|
-
module ActiveSupport
|
42
|
-
class TestCase
|
43
|
-
if using_mysql?
|
44
|
-
if respond_to? :use_transactional_tests=
|
45
|
-
self.use_transactional_tests = false
|
46
|
-
else
|
47
|
-
self.use_transactional_fixtures = false
|
48
|
-
end
|
49
|
-
setup { DatabaseCleaner.start }
|
50
|
-
end
|
51
|
-
|
52
|
-
teardown do
|
53
|
-
DatabaseCleaner.clean if using_mysql?
|
54
|
-
Thread.current[:paper_trail] = nil
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def assert_attributes_equal(expected, actual)
|
60
|
-
if using_mysql?
|
61
|
-
expected = expected.dup
|
62
|
-
actual = actual.dup
|
63
|
-
|
64
|
-
# Adjust timestamps for missing fractional seconds precision.
|
65
|
-
%w(created_at updated_at).each do |timestamp|
|
66
|
-
expected[timestamp] = expected[timestamp].change(usec: 0)
|
67
|
-
actual[timestamp] = actual[timestamp].change(usec: 0)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
assert_equal expected, actual
|
72
|
-
end
|
73
|
-
|
74
|
-
def assert_changes_equal(expected, actual)
|
75
|
-
if using_mysql?
|
76
|
-
expected = expected.dup
|
77
|
-
actual = actual.dup
|
78
|
-
|
79
|
-
# Adjust timestamps for missing fractional seconds precision.
|
80
|
-
%w(created_at updated_at).each do |timestamp|
|
81
|
-
expected[timestamp][1] = expected[timestamp][1].change(usec: 0)
|
82
|
-
actual[timestamp][1] = actual[timestamp][1].change(usec: 0)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
assert_equal expected, actual
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
#
|
92
|
-
# Helpers
|
93
|
-
#
|
94
|
-
|
95
|
-
def change_schema
|
96
|
-
ActiveRecord::Migration.verbose = false
|
97
|
-
ActiveRecord::Schema.define do
|
98
|
-
add_column :versions, :custom_created_at, :datetime
|
99
|
-
end
|
100
|
-
ActiveRecord::Migration.verbose = true
|
101
|
-
reset_version_class_column_info!
|
102
|
-
end
|
103
|
-
|
104
|
-
# Wrap args in a hash to support the ActionController::TestCase and
|
105
|
-
# ActionDispatch::Integration HTTP request method switch to keyword args
|
106
|
-
# (see https://github.com/rails/rails/blob/master/actionpack/CHANGELOG.md)
|
107
|
-
def params_wrapper(args)
|
108
|
-
if defined?(::Rails) && active_record_gem_version >= Gem::Version.new("5.0.0.beta1")
|
109
|
-
{ params: args }
|
110
|
-
else
|
111
|
-
args
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def reset_version_class_column_info!
|
116
|
-
PaperTrail::Version.connection.schema_cache.clear!
|
117
|
-
PaperTrail::Version.reset_column_information
|
118
|
-
end
|
119
|
-
|
120
|
-
def restore_schema
|
121
|
-
ActiveRecord::Migration.verbose = false
|
122
|
-
ActiveRecord::Schema.define do
|
123
|
-
remove_column :versions, :custom_created_at
|
124
|
-
end
|
125
|
-
ActiveRecord::Migration.verbose = true
|
126
|
-
reset_version_class_column_info!
|
127
|
-
end
|
data/test/time_travel_helper.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require "timecop"
|
@@ -1,1016 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "time_travel_helper"
|
3
|
-
|
4
|
-
class AssociationsTest < ActiveSupport::TestCase
|
5
|
-
CHAPTER_NAMES = [
|
6
|
-
"Down the Rabbit-Hole",
|
7
|
-
"The Pool of Tears",
|
8
|
-
"A Caucus-Race and a Long Tale",
|
9
|
-
"The Rabbit Sends in a Little Bill",
|
10
|
-
"Advice from a Caterpillar",
|
11
|
-
"Pig and Pepper",
|
12
|
-
"A Mad Tea-Party",
|
13
|
-
"The Queen's Croquet-Ground",
|
14
|
-
"The Mock Turtle's Story",
|
15
|
-
"The Lobster Quadrille",
|
16
|
-
"Who Stole the Tarts?",
|
17
|
-
"Alice's Evidence"
|
18
|
-
].freeze
|
19
|
-
|
20
|
-
# These would have been done in test_helper.rb if using_mysql? is true
|
21
|
-
unless using_mysql?
|
22
|
-
if respond_to? :use_transactional_tests=
|
23
|
-
self.use_transactional_tests = false
|
24
|
-
else
|
25
|
-
self.use_transactional_fixtures = false
|
26
|
-
end
|
27
|
-
setup { DatabaseCleaner.start }
|
28
|
-
end
|
29
|
-
|
30
|
-
teardown do
|
31
|
-
Timecop.return
|
32
|
-
# This would have been done in test_helper.rb if using_mysql? is true
|
33
|
-
DatabaseCleaner.clean unless using_mysql?
|
34
|
-
end
|
35
|
-
|
36
|
-
context "a has_one association" do
|
37
|
-
setup { @widget = Widget.create name: "widget_0" }
|
38
|
-
|
39
|
-
context "before the associated was created" do
|
40
|
-
setup do
|
41
|
-
@widget.update_attributes name: "widget_1"
|
42
|
-
@wotsit = @widget.create_wotsit name: "wotsit_0"
|
43
|
-
end
|
44
|
-
|
45
|
-
context "when reified" do
|
46
|
-
setup { @widget_0 = @widget.versions.last.reify(has_one: true) }
|
47
|
-
|
48
|
-
should "see the associated as it was at the time" do
|
49
|
-
assert_nil @widget_0.wotsit
|
50
|
-
end
|
51
|
-
|
52
|
-
should "not persist changes to the live association" do
|
53
|
-
assert_equal @wotsit, @widget.reload.wotsit
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
context "where the association is created between model versions" do
|
59
|
-
setup do
|
60
|
-
@wotsit = @widget.create_wotsit name: "wotsit_0"
|
61
|
-
Timecop.travel 1.second.since
|
62
|
-
@widget.update_attributes name: "widget_1"
|
63
|
-
end
|
64
|
-
|
65
|
-
context "when reified" do
|
66
|
-
setup { @widget_0 = @widget.versions.last.reify(has_one: true) }
|
67
|
-
|
68
|
-
should "see the associated as it was at the time" do
|
69
|
-
assert_equal "wotsit_0", @widget_0.wotsit.name
|
70
|
-
end
|
71
|
-
|
72
|
-
should "not persist changes to the live association" do
|
73
|
-
assert_equal @wotsit, @widget.reload.wotsit
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context "and then the associated is updated between model versions" do
|
78
|
-
setup do
|
79
|
-
@wotsit.update_attributes name: "wotsit_1"
|
80
|
-
@wotsit.update_attributes name: "wotsit_2"
|
81
|
-
Timecop.travel 1.second.since
|
82
|
-
@widget.update_attributes name: "widget_2"
|
83
|
-
@wotsit.update_attributes name: "wotsit_3"
|
84
|
-
end
|
85
|
-
|
86
|
-
context "when reified" do
|
87
|
-
setup { @widget_1 = @widget.versions.last.reify(has_one: true) }
|
88
|
-
|
89
|
-
should "see the associated as it was at the time" do
|
90
|
-
assert_equal "wotsit_2", @widget_1.wotsit.name
|
91
|
-
end
|
92
|
-
|
93
|
-
should "not persist changes to the live association" do
|
94
|
-
assert_equal "wotsit_3", @widget.reload.wotsit.name
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
context "when reified opting out of has_one reification" do
|
99
|
-
setup { @widget_1 = @widget.versions.last.reify(has_one: false) }
|
100
|
-
|
101
|
-
should "see the associated as it is live" do
|
102
|
-
assert_equal "wotsit_3", @widget_1.wotsit.name
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context "and then the associated is destroyed" do
|
108
|
-
setup do
|
109
|
-
@wotsit.destroy
|
110
|
-
end
|
111
|
-
|
112
|
-
context "when reify" do
|
113
|
-
setup { @widget_1 = @widget.versions.last.reify(has_one: true) }
|
114
|
-
|
115
|
-
should "see the associated as it was at the time" do
|
116
|
-
assert_equal @wotsit, @widget_1.wotsit
|
117
|
-
end
|
118
|
-
|
119
|
-
should "not persist changes to the live association" do
|
120
|
-
assert_nil @widget.reload.wotsit
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
context "and then the model is updated" do
|
125
|
-
setup do
|
126
|
-
Timecop.travel 1.second.since
|
127
|
-
@widget.update_attributes name: "widget_3"
|
128
|
-
end
|
129
|
-
|
130
|
-
context "when reified" do
|
131
|
-
setup { @widget_2 = @widget.versions.last.reify(has_one: true) }
|
132
|
-
|
133
|
-
should "see the associated as it was at the time" do
|
134
|
-
assert_nil @widget_2.wotsit
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
context "a has_many association" do
|
143
|
-
setup { @customer = Customer.create name: "customer_0" }
|
144
|
-
|
145
|
-
context "updated before the associated was created" do
|
146
|
-
setup do
|
147
|
-
@customer.update_attributes! name: "customer_1"
|
148
|
-
@customer.orders.create! order_date: Date.today
|
149
|
-
end
|
150
|
-
|
151
|
-
context "when reified" do
|
152
|
-
setup { @customer_0 = @customer.versions.last.reify(has_many: true) }
|
153
|
-
|
154
|
-
should "see the associated as it was at the time" do
|
155
|
-
assert_equal [], @customer_0.orders
|
156
|
-
end
|
157
|
-
|
158
|
-
should "not persist changes to the live association" do
|
159
|
-
assert_not_equal [], @customer.orders.reload
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
context "when reified with option mark_for_destruction" do
|
164
|
-
should "mark the associated for destruction" do
|
165
|
-
@customer_0 = @customer.versions.last.reify(
|
166
|
-
has_many: true,
|
167
|
-
mark_for_destruction: true
|
168
|
-
)
|
169
|
-
assert_equal [true], @customer_0.orders.map(&:marked_for_destruction?)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context "where the association is created between model versions" do
|
175
|
-
setup do
|
176
|
-
@order = @customer.orders.create! order_date: "order_date_0"
|
177
|
-
Timecop.travel 1.second.since
|
178
|
-
@customer.update_attributes name: "customer_1"
|
179
|
-
end
|
180
|
-
|
181
|
-
context "when reified" do
|
182
|
-
setup { @customer_0 = @customer.versions.last.reify(has_many: true) }
|
183
|
-
|
184
|
-
should "see the associated as it was at the time" do
|
185
|
-
assert_equal ["order_date_0"], @customer_0.orders.map(&:order_date)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
context "and then a nested has_many association is created" do
|
190
|
-
setup do
|
191
|
-
@order.line_items.create! product: "product_0"
|
192
|
-
end
|
193
|
-
|
194
|
-
context "when reified" do
|
195
|
-
setup { @customer_0 = @customer.versions.last.reify(has_many: true) }
|
196
|
-
|
197
|
-
should "see the live version of the nested association" do
|
198
|
-
assert_equal ["product_0"], @customer_0.orders.first.line_items.map(&:product)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
context "and then the associated is updated between model versions" do
|
204
|
-
setup do
|
205
|
-
@order.update_attributes order_date: "order_date_1"
|
206
|
-
@order.update_attributes order_date: "order_date_2"
|
207
|
-
Timecop.travel 1.second.since
|
208
|
-
@customer.update_attributes name: "customer_2"
|
209
|
-
@order.update_attributes order_date: "order_date_3"
|
210
|
-
end
|
211
|
-
|
212
|
-
context "when reified" do
|
213
|
-
setup { @customer_1 = @customer.versions.last.reify(has_many: true) }
|
214
|
-
|
215
|
-
should "see the associated as it was at the time" do
|
216
|
-
assert_equal ["order_date_2"], @customer_1.orders.map(&:order_date)
|
217
|
-
end
|
218
|
-
|
219
|
-
should "not persist changes to the live association" do
|
220
|
-
assert_equal ["order_date_3"], @customer.orders.reload.map(&:order_date)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
context "when reified opting out of has_many reification" do
|
225
|
-
setup { @customer_1 = @customer.versions.last.reify(has_many: false) }
|
226
|
-
|
227
|
-
should "see the associated as it is live" do
|
228
|
-
assert_equal ["order_date_3"], @customer_1.orders.map(&:order_date)
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
context "and then the associated is destroyed" do
|
233
|
-
setup do
|
234
|
-
@order.destroy
|
235
|
-
end
|
236
|
-
|
237
|
-
context "when reified" do
|
238
|
-
setup { @customer_1 = @customer.versions.last.reify(has_many: true) }
|
239
|
-
|
240
|
-
should "see the associated as it was at the time" do
|
241
|
-
assert_equal ["order_date_2"], @customer_1.orders.map(&:order_date)
|
242
|
-
end
|
243
|
-
|
244
|
-
should "not persist changes to the live association" do
|
245
|
-
assert_equal [], @customer.orders.reload
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
context "and then the associated is destroyed" do
|
252
|
-
setup do
|
253
|
-
@order.destroy
|
254
|
-
end
|
255
|
-
|
256
|
-
context "when reified" do
|
257
|
-
setup { @customer_1 = @customer.versions.last.reify(has_many: true) }
|
258
|
-
|
259
|
-
should "see the associated as it was at the time" do
|
260
|
-
assert_equal [@order.order_date], @customer_1.orders.map(&:order_date)
|
261
|
-
end
|
262
|
-
|
263
|
-
should "not persist changes to the live association" do
|
264
|
-
assert_equal [], @customer.orders.reload
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
context "and then the associated is destroyed between model versions" do
|
270
|
-
setup do
|
271
|
-
@order.destroy
|
272
|
-
Timecop.travel 1.second.since
|
273
|
-
@customer.update_attributes name: "customer_2"
|
274
|
-
end
|
275
|
-
|
276
|
-
context "when reified" do
|
277
|
-
setup { @customer_1 = @customer.versions.last.reify(has_many: true) }
|
278
|
-
|
279
|
-
should "see the associated as it was at the time" do
|
280
|
-
assert_equal [], @customer_1.orders
|
281
|
-
end
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
context "and then another association is added" do
|
286
|
-
setup do
|
287
|
-
@customer.orders.create! order_date: "order_date_1"
|
288
|
-
end
|
289
|
-
|
290
|
-
context "when reified" do
|
291
|
-
setup { @customer_0 = @customer.versions.last.reify(has_many: true) }
|
292
|
-
|
293
|
-
should "see the associated as it was at the time" do
|
294
|
-
assert_equal ["order_date_0"], @customer_0.orders.map(&:order_date)
|
295
|
-
end
|
296
|
-
|
297
|
-
should "not persist changes to the live association" do
|
298
|
-
assert_equal %w(order_date_0 order_date_1),
|
299
|
-
@customer.orders.reload.map(&:order_date).sort
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
context "when reified with option mark_for_destruction" do
|
304
|
-
should "mark the newly associated for destruction" do
|
305
|
-
@customer_0 = @customer.versions.last.reify(
|
306
|
-
has_many: true,
|
307
|
-
mark_for_destruction: true
|
308
|
-
)
|
309
|
-
assert @customer_0.
|
310
|
-
orders.
|
311
|
-
detect { |o| o.order_date == "order_date_1" }.
|
312
|
-
marked_for_destruction?
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
context "has_many through associations" do
|
320
|
-
context "Books, Authors, and Authorships" do
|
321
|
-
setup { @book = Book.create title: "book_0" }
|
322
|
-
|
323
|
-
context "updated before the associated was created" do
|
324
|
-
setup do
|
325
|
-
@book.update_attributes! title: "book_1"
|
326
|
-
@book.authors.create! name: "author_0"
|
327
|
-
end
|
328
|
-
|
329
|
-
context "when reified" do
|
330
|
-
setup { @book_0 = @book.versions.last.reify(has_many: true) }
|
331
|
-
|
332
|
-
should "see the associated as it was at the time" do
|
333
|
-
assert_equal [], @book_0.authors
|
334
|
-
end
|
335
|
-
|
336
|
-
should "not persist changes to the live association" do
|
337
|
-
assert_equal ["author_0"], @book.authors.reload.map(&:name)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
context "when reified with option mark_for_destruction" do
|
342
|
-
setup do
|
343
|
-
@book_0 = @book.versions.last.reify(
|
344
|
-
has_many: true,
|
345
|
-
mark_for_destruction: true
|
346
|
-
)
|
347
|
-
end
|
348
|
-
|
349
|
-
should "mark the associated for destruction" do
|
350
|
-
assert_equal [true], @book_0.authors.map(&:marked_for_destruction?)
|
351
|
-
end
|
352
|
-
|
353
|
-
should "mark the associated-through for destruction" do
|
354
|
-
assert_equal [true], @book_0.authorships.map(&:marked_for_destruction?)
|
355
|
-
end
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
context "updated before it is associated with an existing one" do
|
360
|
-
setup do
|
361
|
-
person_existing = Person.create(name: "person_existing")
|
362
|
-
Timecop.travel 1.second.since
|
363
|
-
@book.update_attributes! title: "book_1"
|
364
|
-
@book.authors << person_existing
|
365
|
-
end
|
366
|
-
|
367
|
-
context "when reified" do
|
368
|
-
setup do
|
369
|
-
@book_0 = @book.versions.last.reify(has_many: true)
|
370
|
-
end
|
371
|
-
|
372
|
-
should "see the associated as it was at the time" do
|
373
|
-
assert_equal [], @book_0.authors
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
context "when reified with option mark_for_destruction" do
|
378
|
-
setup do
|
379
|
-
@book_0 = @book.versions.last.reify(
|
380
|
-
has_many: true,
|
381
|
-
mark_for_destruction: true
|
382
|
-
)
|
383
|
-
end
|
384
|
-
|
385
|
-
should "not mark the associated for destruction" do
|
386
|
-
assert_equal [false], @book_0.authors.map(&:marked_for_destruction?)
|
387
|
-
end
|
388
|
-
|
389
|
-
should "mark the associated-through for destruction" do
|
390
|
-
assert_equal [true], @book_0.authorships.map(&:marked_for_destruction?)
|
391
|
-
end
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
context "where the association is created between model versions" do
|
396
|
-
setup do
|
397
|
-
@author = @book.authors.create! name: "author_0"
|
398
|
-
@person_existing = Person.create(name: "person_existing")
|
399
|
-
Timecop.travel 1.second.since
|
400
|
-
@book.update_attributes! title: "book_1"
|
401
|
-
end
|
402
|
-
|
403
|
-
context "when reified" do
|
404
|
-
setup { @book_0 = @book.versions.last.reify(has_many: true) }
|
405
|
-
|
406
|
-
should "see the associated as it was at the time" do
|
407
|
-
assert_equal ["author_0"], @book_0.authors.map(&:name)
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
context "and then the associated is updated between model versions" do
|
412
|
-
setup do
|
413
|
-
@author.update_attributes name: "author_1"
|
414
|
-
@author.update_attributes name: "author_2"
|
415
|
-
Timecop.travel 1.second.since
|
416
|
-
@book.update_attributes title: "book_2"
|
417
|
-
@author.update_attributes name: "author_3"
|
418
|
-
end
|
419
|
-
|
420
|
-
context "when reified" do
|
421
|
-
setup { @book_1 = @book.versions.last.reify(has_many: true) }
|
422
|
-
|
423
|
-
should "see the associated as it was at the time" do
|
424
|
-
assert_equal ["author_2"], @book_1.authors.map(&:name)
|
425
|
-
end
|
426
|
-
|
427
|
-
should "not persist changes to the live association" do
|
428
|
-
assert_equal ["author_3"], @book.authors.reload.map(&:name)
|
429
|
-
end
|
430
|
-
end
|
431
|
-
|
432
|
-
context "when reified opting out of has_many reification" do
|
433
|
-
setup { @book_1 = @book.versions.last.reify(has_many: false) }
|
434
|
-
|
435
|
-
should "see the associated as it is live" do
|
436
|
-
assert_equal ["author_3"], @book_1.authors.map(&:name)
|
437
|
-
end
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
context "and then the associated is destroyed" do
|
442
|
-
setup do
|
443
|
-
@author.destroy
|
444
|
-
end
|
445
|
-
|
446
|
-
context "when reified" do
|
447
|
-
setup { @book_1 = @book.versions.last.reify(has_many: true) }
|
448
|
-
|
449
|
-
should "see the associated as it was at the time" do
|
450
|
-
assert_equal [@author.name], @book_1.authors.map(&:name)
|
451
|
-
end
|
452
|
-
|
453
|
-
should "not persist changes to the live association" do
|
454
|
-
assert_equal [], @book.authors.reload
|
455
|
-
end
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
context "and then the associated is destroyed between model versions" do
|
460
|
-
setup do
|
461
|
-
@author.destroy
|
462
|
-
Timecop.travel 1.second.since
|
463
|
-
@book.update_attributes title: "book_2"
|
464
|
-
end
|
465
|
-
|
466
|
-
context "when reified" do
|
467
|
-
setup { @book_1 = @book.versions.last.reify(has_many: true) }
|
468
|
-
|
469
|
-
should "see the associated as it was at the time" do
|
470
|
-
assert_equal [], @book_1.authors
|
471
|
-
end
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
context "and then the associated is dissociated between model versions" do
|
476
|
-
setup do
|
477
|
-
@book.authors = []
|
478
|
-
Timecop.travel 1.second.since
|
479
|
-
@book.update_attributes title: "book_2"
|
480
|
-
end
|
481
|
-
|
482
|
-
context "when reified" do
|
483
|
-
setup { @book_1 = @book.versions.last.reify(has_many: true) }
|
484
|
-
|
485
|
-
should "see the associated as it was at the time" do
|
486
|
-
assert_equal [], @book_1.authors
|
487
|
-
end
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
context "and then another associated is created" do
|
492
|
-
setup do
|
493
|
-
@book.authors.create! name: "author_1"
|
494
|
-
end
|
495
|
-
|
496
|
-
context "when reified" do
|
497
|
-
setup { @book_0 = @book.versions.last.reify(has_many: true) }
|
498
|
-
|
499
|
-
should "only see the first associated" do
|
500
|
-
assert_equal ["author_0"], @book_0.authors.map(&:name)
|
501
|
-
end
|
502
|
-
|
503
|
-
should "not persist changes to the live association" do
|
504
|
-
assert_equal %w(author_0 author_1), @book.authors.reload.map(&:name)
|
505
|
-
end
|
506
|
-
end
|
507
|
-
|
508
|
-
context "when reified with option mark_for_destruction" do
|
509
|
-
setup do
|
510
|
-
@book_0 = @book.versions.last.reify(
|
511
|
-
has_many: true,
|
512
|
-
mark_for_destruction: true
|
513
|
-
)
|
514
|
-
end
|
515
|
-
|
516
|
-
should "mark the newly associated for destruction" do
|
517
|
-
assert @book_0.
|
518
|
-
authors.
|
519
|
-
detect { |a| a.name == "author_1" }.
|
520
|
-
marked_for_destruction?
|
521
|
-
end
|
522
|
-
|
523
|
-
should "mark the newly associated-through for destruction" do
|
524
|
-
assert @book_0.
|
525
|
-
authorships.
|
526
|
-
detect { |as| as.author.name == "author_1" }.
|
527
|
-
marked_for_destruction?
|
528
|
-
end
|
529
|
-
end
|
530
|
-
end
|
531
|
-
|
532
|
-
context "and then an existing one is associated" do
|
533
|
-
setup do
|
534
|
-
@book.authors << @person_existing
|
535
|
-
end
|
536
|
-
|
537
|
-
context "when reified" do
|
538
|
-
setup { @book_0 = @book.versions.last.reify(has_many: true) }
|
539
|
-
|
540
|
-
should "only see the first associated" do
|
541
|
-
assert_equal ["author_0"], @book_0.authors.map(&:name)
|
542
|
-
end
|
543
|
-
|
544
|
-
should "not persist changes to the live association" do
|
545
|
-
assert_equal %w(author_0 person_existing), @book.authors.reload.map(&:name).sort
|
546
|
-
end
|
547
|
-
end
|
548
|
-
|
549
|
-
context "when reified with option mark_for_destruction" do
|
550
|
-
setup do
|
551
|
-
@book_0 = @book.versions.last.reify(
|
552
|
-
has_many: true,
|
553
|
-
mark_for_destruction: true
|
554
|
-
)
|
555
|
-
end
|
556
|
-
|
557
|
-
should "not mark the newly associated for destruction" do
|
558
|
-
assert !@book_0.
|
559
|
-
authors.
|
560
|
-
detect { |a| a.name == "person_existing" }.
|
561
|
-
marked_for_destruction?
|
562
|
-
end
|
563
|
-
|
564
|
-
should "mark the newly associated-through for destruction" do
|
565
|
-
assert @book_0.
|
566
|
-
authorships.
|
567
|
-
detect { |as| as.author.name == "person_existing" }.
|
568
|
-
marked_for_destruction?
|
569
|
-
end
|
570
|
-
end
|
571
|
-
end
|
572
|
-
end
|
573
|
-
|
574
|
-
context "updated before the associated without paper_trail was created" do
|
575
|
-
setup do
|
576
|
-
@book.update_attributes! title: "book_1"
|
577
|
-
@book.editors.create! name: "editor_0"
|
578
|
-
end
|
579
|
-
|
580
|
-
context "when reified" do
|
581
|
-
setup { @book_0 = @book.versions.last.reify(has_many: true) }
|
582
|
-
|
583
|
-
should "see the live association" do
|
584
|
-
assert_equal ["editor_0"], @book_0.editors.map(&:name)
|
585
|
-
end
|
586
|
-
end
|
587
|
-
end
|
588
|
-
end
|
589
|
-
|
590
|
-
context "Chapters, Sections, Paragraphs, Quotations, and Citations" do
|
591
|
-
setup { @chapter = Chapter.create(name: CHAPTER_NAMES[0]) }
|
592
|
-
|
593
|
-
context "before any associations are created" do
|
594
|
-
setup do
|
595
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[1])
|
596
|
-
end
|
597
|
-
|
598
|
-
should "not reify any associations" do
|
599
|
-
chapter_v1 = @chapter.versions[1].reify(has_many: true)
|
600
|
-
assert_equal CHAPTER_NAMES[0], chapter_v1.name
|
601
|
-
assert_equal [], chapter_v1.sections
|
602
|
-
assert_equal [], chapter_v1.paragraphs
|
603
|
-
end
|
604
|
-
end
|
605
|
-
|
606
|
-
context "after the first has_many through relationship is created" do
|
607
|
-
setup do
|
608
|
-
assert_equal 1, @chapter.versions.size
|
609
|
-
@chapter.update_attributes name: CHAPTER_NAMES[1]
|
610
|
-
assert_equal 2, @chapter.versions.size
|
611
|
-
|
612
|
-
Timecop.travel 1.second.since
|
613
|
-
@chapter.sections.create name: "section 1"
|
614
|
-
Timecop.travel 1.second.since
|
615
|
-
@chapter.sections.first.update_attributes name: "section 2"
|
616
|
-
Timecop.travel 1.second.since
|
617
|
-
@chapter.update_attributes name: CHAPTER_NAMES[2]
|
618
|
-
assert_equal 3, @chapter.versions.size
|
619
|
-
|
620
|
-
Timecop.travel 1.second.since
|
621
|
-
@chapter.sections.first.update_attributes name: "section 3"
|
622
|
-
end
|
623
|
-
|
624
|
-
context "version 1" do
|
625
|
-
should "have no sections" do
|
626
|
-
chapter_v1 = @chapter.versions[1].reify(has_many: true)
|
627
|
-
assert_equal [], chapter_v1.sections
|
628
|
-
end
|
629
|
-
end
|
630
|
-
|
631
|
-
context "version 2" do
|
632
|
-
should "have one section" do
|
633
|
-
chapter_v2 = @chapter.versions[2].reify(has_many: true)
|
634
|
-
assert_equal 1, chapter_v2.sections.size
|
635
|
-
|
636
|
-
# Shows the value of the section as it was before
|
637
|
-
# the chapter was updated.
|
638
|
-
assert_equal ["section 2"], chapter_v2.sections.map(&:name)
|
639
|
-
|
640
|
-
# Shows the value of the chapter as it was before
|
641
|
-
assert_equal CHAPTER_NAMES[1], chapter_v2.name
|
642
|
-
end
|
643
|
-
end
|
644
|
-
|
645
|
-
context "version 2, before the section was destroyed" do
|
646
|
-
setup do
|
647
|
-
@chapter.update_attributes name: CHAPTER_NAMES[2]
|
648
|
-
Timecop.travel 1.second.since
|
649
|
-
@chapter.sections.destroy_all
|
650
|
-
Timecop.travel 1.second.since
|
651
|
-
end
|
652
|
-
|
653
|
-
should "have the one section" do
|
654
|
-
chapter_v2 = @chapter.versions[2].reify(has_many: true)
|
655
|
-
assert_equal ["section 2"], chapter_v2.sections.map(&:name)
|
656
|
-
end
|
657
|
-
end
|
658
|
-
|
659
|
-
context "version 3, after the section was destroyed" do
|
660
|
-
setup do
|
661
|
-
@chapter.sections.destroy_all
|
662
|
-
Timecop.travel 1.second.since
|
663
|
-
@chapter.update_attributes name: CHAPTER_NAMES[3]
|
664
|
-
Timecop.travel 1.second.since
|
665
|
-
end
|
666
|
-
|
667
|
-
should "have no sections" do
|
668
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
669
|
-
assert_equal 0, chapter_v3.sections.size
|
670
|
-
end
|
671
|
-
end
|
672
|
-
|
673
|
-
context "after creating a paragraph" do
|
674
|
-
setup do
|
675
|
-
assert_equal 3, @chapter.versions.size
|
676
|
-
@section = @chapter.sections.first
|
677
|
-
Timecop.travel 1.second.since
|
678
|
-
@paragraph = @section.paragraphs.create name: "para1"
|
679
|
-
end
|
680
|
-
|
681
|
-
context "new chapter version" do
|
682
|
-
should "have one paragraph" do
|
683
|
-
initial_section_name = @section.name
|
684
|
-
initial_paragraph_name = @paragraph.name
|
685
|
-
Timecop.travel 1.second.since
|
686
|
-
@chapter.update_attributes name: CHAPTER_NAMES[4]
|
687
|
-
assert_equal 4, @chapter.versions.size
|
688
|
-
Timecop.travel 1.second.since
|
689
|
-
@paragraph.update_attributes name: "para3"
|
690
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
691
|
-
assert_equal [initial_section_name], chapter_v3.sections.map(&:name)
|
692
|
-
paragraphs = chapter_v3.sections.first.paragraphs
|
693
|
-
assert_equal 1, paragraphs.size
|
694
|
-
assert_equal [initial_paragraph_name], paragraphs.map(&:name)
|
695
|
-
end
|
696
|
-
end
|
697
|
-
|
698
|
-
context "the version before a section is destroyed" do
|
699
|
-
should "have the section and paragraph" do
|
700
|
-
Timecop.travel 1.second.since
|
701
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[3])
|
702
|
-
assert_equal 4, @chapter.versions.size
|
703
|
-
Timecop.travel 1.second.since
|
704
|
-
@section.destroy
|
705
|
-
assert_equal 4, @chapter.versions.size
|
706
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
707
|
-
assert_equal CHAPTER_NAMES[2], chapter_v3.name
|
708
|
-
assert_equal [@section], chapter_v3.sections
|
709
|
-
assert_equal [@paragraph], chapter_v3.sections[0].paragraphs
|
710
|
-
assert_equal [@paragraph], chapter_v3.paragraphs
|
711
|
-
end
|
712
|
-
end
|
713
|
-
|
714
|
-
context "the version after a section is destroyed" do
|
715
|
-
should "not have any sections or paragraphs" do
|
716
|
-
@section.destroy
|
717
|
-
Timecop.travel 1.second.since
|
718
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[5])
|
719
|
-
assert_equal 4, @chapter.versions.size
|
720
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
721
|
-
assert_equal 0, chapter_v3.sections.size
|
722
|
-
assert_equal 0, chapter_v3.paragraphs.size
|
723
|
-
end
|
724
|
-
end
|
725
|
-
|
726
|
-
context "the version before a paragraph is destroyed" do
|
727
|
-
should "have the one paragraph" do
|
728
|
-
initial_paragraph_name = @section.paragraphs.first.name
|
729
|
-
Timecop.travel 1.second.since
|
730
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[5])
|
731
|
-
Timecop.travel 1.second.since
|
732
|
-
@paragraph.destroy
|
733
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
734
|
-
paragraphs = chapter_v3.sections.first.paragraphs
|
735
|
-
assert_equal 1, paragraphs.size
|
736
|
-
assert_equal initial_paragraph_name, paragraphs.first.name
|
737
|
-
end
|
738
|
-
end
|
739
|
-
|
740
|
-
context "the version after a paragraph is destroyed" do
|
741
|
-
should "have no paragraphs" do
|
742
|
-
@paragraph.destroy
|
743
|
-
Timecop.travel 1.second.since
|
744
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[5])
|
745
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
746
|
-
assert_equal 0, chapter_v3.paragraphs.size
|
747
|
-
assert_equal [], chapter_v3.sections.first.paragraphs
|
748
|
-
end
|
749
|
-
end
|
750
|
-
end
|
751
|
-
end
|
752
|
-
|
753
|
-
context "a chapter with one paragraph and one citation" do
|
754
|
-
should "reify paragraphs and citations" do
|
755
|
-
chapter = Chapter.create(name: CHAPTER_NAMES[0])
|
756
|
-
section = Section.create(name: "Section One", chapter: chapter)
|
757
|
-
paragraph = Paragraph.create(name: "Paragraph One", section: section)
|
758
|
-
quotation = Quotation.create(chapter: chapter)
|
759
|
-
citation = Citation.create(quotation: quotation)
|
760
|
-
Timecop.travel 1.second.since
|
761
|
-
chapter.update_attributes(name: CHAPTER_NAMES[1])
|
762
|
-
assert_equal 2, chapter.versions.count
|
763
|
-
paragraph.destroy
|
764
|
-
citation.destroy
|
765
|
-
reified = chapter.versions[1].reify(has_many: true)
|
766
|
-
assert_equal [paragraph], reified.sections.first.paragraphs
|
767
|
-
assert_equal [citation], reified.quotations.first.citations
|
768
|
-
end
|
769
|
-
end
|
770
|
-
end
|
771
|
-
end
|
772
|
-
|
773
|
-
context "belongs_to associations" do
|
774
|
-
context "Wotsit and Widget" do
|
775
|
-
setup { @widget = Widget.create(name: "widget_0") }
|
776
|
-
|
777
|
-
context "where the association is created between model versions" do
|
778
|
-
setup do
|
779
|
-
@wotsit = Wotsit.create(name: "wotsit_0")
|
780
|
-
Timecop.travel 1.second.since
|
781
|
-
@wotsit.update_attributes widget_id: @widget.id, name: "wotsit_1"
|
782
|
-
end
|
783
|
-
|
784
|
-
context "when reified" do
|
785
|
-
setup { @wotsit_0 = @wotsit.versions.last.reify(belongs_to: true) }
|
786
|
-
|
787
|
-
should "see the associated as it was at the time" do
|
788
|
-
assert_equal nil, @wotsit_0.widget
|
789
|
-
end
|
790
|
-
|
791
|
-
should "not persist changes to the live association" do
|
792
|
-
assert_equal @widget, @wotsit.reload.widget
|
793
|
-
end
|
794
|
-
end
|
795
|
-
|
796
|
-
context "and then the associated is updated between model versions" do
|
797
|
-
setup do
|
798
|
-
@widget.update_attributes name: "widget_1"
|
799
|
-
@widget.update_attributes name: "widget_2"
|
800
|
-
Timecop.travel 1.second.since
|
801
|
-
@wotsit.update_attributes name: "wotsit_2"
|
802
|
-
@widget.update_attributes name: "widget_3"
|
803
|
-
end
|
804
|
-
|
805
|
-
context "when reified" do
|
806
|
-
setup { @wotsit_1 = @wotsit.versions.last.reify(belongs_to: true) }
|
807
|
-
|
808
|
-
should "see the associated as it was at the time" do
|
809
|
-
assert_equal "widget_2", @wotsit_1.widget.name
|
810
|
-
end
|
811
|
-
|
812
|
-
should "not persist changes to the live association" do
|
813
|
-
assert_equal "widget_3", @wotsit.reload.widget.name
|
814
|
-
end
|
815
|
-
end
|
816
|
-
|
817
|
-
context "when reified opting out of belongs_to reification" do
|
818
|
-
setup { @wotsit_1 = @wotsit.versions.last.reify(belongs_to: false) }
|
819
|
-
|
820
|
-
should "see the associated as it is live" do
|
821
|
-
assert_equal "widget_3", @wotsit_1.widget.name
|
822
|
-
end
|
823
|
-
end
|
824
|
-
end
|
825
|
-
|
826
|
-
context "and then the associated is destroyed" do
|
827
|
-
setup do
|
828
|
-
@wotsit.update_attributes name: "wotsit_2"
|
829
|
-
@widget.destroy
|
830
|
-
end
|
831
|
-
|
832
|
-
context "when reified" do
|
833
|
-
setup { @wotsit_2 = @wotsit.versions.last.reify(belongs_to: true) }
|
834
|
-
|
835
|
-
should "see the associated as it was at the time" do
|
836
|
-
assert_equal @widget, @wotsit_2.widget
|
837
|
-
end
|
838
|
-
|
839
|
-
should "not persist changes to the live association" do
|
840
|
-
assert_nil @wotsit.reload.widget
|
841
|
-
end
|
842
|
-
end
|
843
|
-
|
844
|
-
context "and then the model is updated" do
|
845
|
-
setup do
|
846
|
-
Timecop.travel 1.second.since
|
847
|
-
@wotsit.update_attributes name: "wotsit_3"
|
848
|
-
end
|
849
|
-
|
850
|
-
context "when reified" do
|
851
|
-
setup { @wotsit_2 = @wotsit.versions.last.reify(belongs_to: true) }
|
852
|
-
|
853
|
-
should "see the associated as it was the time" do
|
854
|
-
assert_nil @wotsit_2.widget
|
855
|
-
end
|
856
|
-
end
|
857
|
-
end
|
858
|
-
end
|
859
|
-
end
|
860
|
-
|
861
|
-
context "where the association is changed between model versions" do
|
862
|
-
setup do
|
863
|
-
@wotsit = @widget.create_wotsit(name: "wotsit_0")
|
864
|
-
Timecop.travel 1.second.since
|
865
|
-
@new_widget = Widget.create(name: "new_widget")
|
866
|
-
@wotsit.update_attributes(widget_id: @new_widget.id, name: "wotsit_1")
|
867
|
-
end
|
868
|
-
|
869
|
-
context "when reified" do
|
870
|
-
setup { @wotsit_0 = @wotsit.versions.last.reify(belongs_to: true) }
|
871
|
-
|
872
|
-
should "see the association as it was at the time" do
|
873
|
-
assert_equal "widget_0", @wotsit_0.widget.name
|
874
|
-
end
|
875
|
-
|
876
|
-
should "not persist changes to the live association" do
|
877
|
-
assert_equal @new_widget, @wotsit.reload.widget
|
878
|
-
end
|
879
|
-
end
|
880
|
-
|
881
|
-
context "when reified with option mark_for_destruction" do
|
882
|
-
setup do
|
883
|
-
@wotsit_0 = @wotsit.versions.last.
|
884
|
-
reify(belongs_to: true, mark_for_destruction: true)
|
885
|
-
end
|
886
|
-
|
887
|
-
should "should not mark the new associated for destruction" do
|
888
|
-
assert_equal false, @new_widget.marked_for_destruction?
|
889
|
-
end
|
890
|
-
end
|
891
|
-
end
|
892
|
-
end
|
893
|
-
end
|
894
|
-
|
895
|
-
context "has_and_belongs_to_many associations" do
|
896
|
-
context "foo and bar" do
|
897
|
-
setup do
|
898
|
-
@foo = FooHabtm.create(name: "foo")
|
899
|
-
Timecop.travel 1.second.since
|
900
|
-
end
|
901
|
-
|
902
|
-
context "where the association is created between model versions" do
|
903
|
-
setup do
|
904
|
-
@foo.update_attributes(name: "foo1", bar_habtms: [BarHabtm.create(name: "bar")])
|
905
|
-
end
|
906
|
-
|
907
|
-
context "when reified" do
|
908
|
-
setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
|
909
|
-
|
910
|
-
should "see the associated as it was at the time" do
|
911
|
-
assert_equal 0, @reified.bar_habtms.length
|
912
|
-
end
|
913
|
-
|
914
|
-
should "not persist changes to the live association" do
|
915
|
-
assert_not_equal @reified.bar_habtms, @foo.reload.bar_habtms
|
916
|
-
end
|
917
|
-
end
|
918
|
-
end
|
919
|
-
|
920
|
-
context "where the association is changed between model versions" do
|
921
|
-
setup do
|
922
|
-
@foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
|
923
|
-
Timecop.travel 1.second.since
|
924
|
-
@foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar3")])
|
925
|
-
end
|
926
|
-
|
927
|
-
context "when reified" do
|
928
|
-
setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
|
929
|
-
|
930
|
-
should "see the association as it was at the time" do
|
931
|
-
assert_equal "bar2", @reified.bar_habtms.first.name
|
932
|
-
end
|
933
|
-
|
934
|
-
should "not persist changes to the live association" do
|
935
|
-
assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
|
936
|
-
end
|
937
|
-
end
|
938
|
-
|
939
|
-
context "when reified with has_and_belongs_to_many: false" do
|
940
|
-
setup { @reified = @foo.versions.last.reify }
|
941
|
-
|
942
|
-
should "see the association as it is now" do
|
943
|
-
assert_equal "bar3", @reified.bar_habtms.first.name
|
944
|
-
end
|
945
|
-
end
|
946
|
-
end
|
947
|
-
|
948
|
-
context "where the association is destroyed between model versions" do
|
949
|
-
setup do
|
950
|
-
@foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
|
951
|
-
Timecop.travel 1.second.since
|
952
|
-
@foo.update_attributes(name: "foo3", bar_habtms: [])
|
953
|
-
end
|
954
|
-
|
955
|
-
context "when reified" do
|
956
|
-
setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
|
957
|
-
|
958
|
-
should "see the association as it was at the time" do
|
959
|
-
assert_equal "bar2", @reified.bar_habtms.first.name
|
960
|
-
end
|
961
|
-
|
962
|
-
should "not persist changes to the live association" do
|
963
|
-
assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
|
964
|
-
end
|
965
|
-
end
|
966
|
-
end
|
967
|
-
|
968
|
-
context "where the unassociated model changes" do
|
969
|
-
setup do
|
970
|
-
@bar = BarHabtm.create(name: "bar2")
|
971
|
-
@foo.update_attributes(name: "foo2", bar_habtms: [@bar])
|
972
|
-
Timecop.travel 1.second.since
|
973
|
-
@foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar4")])
|
974
|
-
Timecop.travel 1.second.since
|
975
|
-
@bar.update_attributes(name: "bar3")
|
976
|
-
end
|
977
|
-
|
978
|
-
context "when reified" do
|
979
|
-
setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
|
980
|
-
|
981
|
-
should "see the association as it was at the time" do
|
982
|
-
assert_equal "bar2", @reified.bar_habtms.first.name
|
983
|
-
end
|
984
|
-
|
985
|
-
should "not persist changes to the live association" do
|
986
|
-
assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
|
987
|
-
end
|
988
|
-
end
|
989
|
-
end
|
990
|
-
end
|
991
|
-
|
992
|
-
context "updated via nested attributes" do
|
993
|
-
setup do
|
994
|
-
@foo = FooHabtm.create(
|
995
|
-
name: "foo",
|
996
|
-
bar_habtms_attributes: [{ name: "bar" }]
|
997
|
-
)
|
998
|
-
Timecop.travel 1.second.since
|
999
|
-
@foo.update_attributes(
|
1000
|
-
name: "foo2",
|
1001
|
-
bar_habtms_attributes: [{ id: @foo.bar_habtms.first.id, name: "bar2" }]
|
1002
|
-
)
|
1003
|
-
|
1004
|
-
@reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
|
1005
|
-
end
|
1006
|
-
|
1007
|
-
should "see the associated object as it was at the time" do
|
1008
|
-
assert_equal "bar", @reified.bar_habtms.first.name
|
1009
|
-
end
|
1010
|
-
|
1011
|
-
should "not persist changes to the live object" do
|
1012
|
-
assert_not_equal @reified.bar_habtms.first.name, @foo.reload.bar_habtms.first.name
|
1013
|
-
end
|
1014
|
-
end
|
1015
|
-
end
|
1016
|
-
end
|