active-fedora 13.1.2 → 13.1.3

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.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/.github_changelog_generator +2 -0
  3. data/CHANGELOG.md +3362 -0
  4. data/CONTRIBUTING.md +23 -1
  5. data/README.md +4 -0
  6. data/active-fedora.gemspec +14 -13
  7. data/lib/active_fedora/version.rb +1 -1
  8. metadata +104 -206
  9. data/spec/config_helper.rb +0 -17
  10. data/spec/fixtures/dino.jpg +0 -0
  11. data/spec/fixtures/dino_jpg_no_file_ext +0 -0
  12. data/spec/fixtures/minivan.jpg +0 -0
  13. data/spec/fixtures/rails_root/config/fake_fedora.yml +0 -7
  14. data/spec/fixtures/rails_root/config/fedora.yml +0 -12
  15. data/spec/fixtures/rails_root/config/solr.yml +0 -15
  16. data/spec/fixtures/rails_root/config/solr_mappings.yml +0 -16
  17. data/spec/fixtures/rails_root/config/solr_mappings_af_0.1.yml +0 -9
  18. data/spec/fixtures/rails_root/config/solr_mappings_bl_2.4.yml +0 -17
  19. data/spec/integration/associations/rdf_spec.rb +0 -61
  20. data/spec/integration/associations_spec.rb +0 -680
  21. data/spec/integration/attached_files_spec.rb +0 -146
  22. data/spec/integration/attributes_spec.rb +0 -73
  23. data/spec/integration/autosave_association_spec.rb +0 -24
  24. data/spec/integration/base_spec.rb +0 -184
  25. data/spec/integration/basic_contains_association_spec.rb +0 -121
  26. data/spec/integration/belongs_to_association_spec.rb +0 -260
  27. data/spec/integration/caching_spec.rb +0 -59
  28. data/spec/integration/clean_connection_spec.rb +0 -21
  29. data/spec/integration/collection_association_spec.rb +0 -166
  30. data/spec/integration/date_time_properties_spec.rb +0 -41
  31. data/spec/integration/delete_all_spec.rb +0 -64
  32. data/spec/integration/direct_container_spec.rb +0 -250
  33. data/spec/integration/directly_contains_one_association_spec.rb +0 -96
  34. data/spec/integration/eradicate_spec.rb +0 -52
  35. data/spec/integration/fedora_solr_sync_spec.rb +0 -30
  36. data/spec/integration/file_fixity_spec.rb +0 -36
  37. data/spec/integration/file_spec.rb +0 -221
  38. data/spec/integration/generators/fedora_generator_spec.rb +0 -26
  39. data/spec/integration/generators/solr_generator_spec.rb +0 -23
  40. data/spec/integration/gone_spec.rb +0 -41
  41. data/spec/integration/has_and_belongs_to_many_associations_spec.rb +0 -414
  42. data/spec/integration/has_many_associations_spec.rb +0 -436
  43. data/spec/integration/has_subresource_spec.rb +0 -34
  44. data/spec/integration/indexing/descendant_fetcher_spec.rb +0 -64
  45. data/spec/integration/indexing_spec.rb +0 -110
  46. data/spec/integration/indirect_container_spec.rb +0 -290
  47. data/spec/integration/json_serialization_spec.rb +0 -32
  48. data/spec/integration/marshal_spec.rb +0 -39
  49. data/spec/integration/nested_attribute_spec.rb +0 -177
  50. data/spec/integration/nested_hash_resources_spec.rb +0 -43
  51. data/spec/integration/persistence_spec.rb +0 -37
  52. data/spec/integration/query_result_builder_spec.rb +0 -37
  53. data/spec/integration/rdf_nested_attributes_spec.rb +0 -85
  54. data/spec/integration/relation_delegation_spec.rb +0 -52
  55. data/spec/integration/relation_spec.rb +0 -117
  56. data/spec/integration/scoped_query_spec.rb +0 -134
  57. data/spec/integration/scoping_spec.rb +0 -48
  58. data/spec/integration/solr_hit_spec.rb +0 -32
  59. data/spec/integration/versionable_spec.rb +0 -256
  60. data/spec/integration/with_metadata_spec.rb +0 -111
  61. data/spec/lib/active_fedora/null_logger_spec.rb +0 -10
  62. data/spec/rcov.opts +0 -2
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_helper.rb +0 -106
  65. data/spec/support/an_active_model.rb +0 -29
  66. data/spec/unit/active_fedora/indexing/inserter_spec.rb +0 -35
  67. data/spec/unit/active_fedora_spec.rb +0 -118
  68. data/spec/unit/aggregation/list_source_spec.rb +0 -134
  69. data/spec/unit/aggregation/ordered_reader_spec.rb +0 -43
  70. data/spec/unit/association_hash_spec.rb +0 -64
  71. data/spec/unit/attached_files_spec.rb +0 -218
  72. data/spec/unit/attributes_spec.rb +0 -146
  73. data/spec/unit/base_active_model_spec.rb +0 -28
  74. data/spec/unit/base_cma_spec.rb +0 -15
  75. data/spec/unit/base_extra_spec.rb +0 -33
  76. data/spec/unit/base_spec.rb +0 -328
  77. data/spec/unit/builder/has_and_belongs_to_many_spec.rb +0 -8
  78. data/spec/unit/callback_spec.rb +0 -65
  79. data/spec/unit/change_set_spec.rb +0 -60
  80. data/spec/unit/checksum_spec.rb +0 -25
  81. data/spec/unit/code_configurator_spec.rb +0 -41
  82. data/spec/unit/collection_proxy_spec.rb +0 -25
  83. data/spec/unit/config_spec.rb +0 -18
  84. data/spec/unit/core/fedora_id_translator_spec.rb +0 -29
  85. data/spec/unit/core/fedora_uri_translator_spec.rb +0 -19
  86. data/spec/unit/core/logger_spec.rb +0 -18
  87. data/spec/unit/core_spec.rb +0 -242
  88. data/spec/unit/default_model_mapper_spec.rb +0 -39
  89. data/spec/unit/fedora_spec.rb +0 -31
  90. data/spec/unit/file/streaming_spec.rb +0 -33
  91. data/spec/unit/file_configurator_spec.rb +0 -295
  92. data/spec/unit/file_io_spec.rb +0 -137
  93. data/spec/unit/file_path_builder_spec.rb +0 -18
  94. data/spec/unit/file_spec.rb +0 -489
  95. data/spec/unit/files_hash_spec.rb +0 -52
  96. data/spec/unit/filter_spec.rb +0 -133
  97. data/spec/unit/finder_methods_spec.rb +0 -154
  98. data/spec/unit/fixity_service_spec.rb +0 -128
  99. data/spec/unit/forbidden_attributes_protection_spec.rb +0 -50
  100. data/spec/unit/has_and_belongs_to_many_association_spec.rb +0 -125
  101. data/spec/unit/has_many_association_spec.rb +0 -131
  102. data/spec/unit/indexers/global_indexer_spec.rb +0 -41
  103. data/spec/unit/indexing/map/index_object_spec.rb +0 -25
  104. data/spec/unit/indexing/map_spec.rb +0 -27
  105. data/spec/unit/indexing_service_spec.rb +0 -28
  106. data/spec/unit/indexing_spec.rb +0 -86
  107. data/spec/unit/inheritance_spec.rb +0 -60
  108. data/spec/unit/ldp_resource_spec.rb +0 -15
  109. data/spec/unit/loadable_from_json_spec.rb +0 -40
  110. data/spec/unit/logger_spec.rb +0 -19
  111. data/spec/unit/model_classifier_spec.rb +0 -49
  112. data/spec/unit/ordered_spec.rb +0 -367
  113. data/spec/unit/orders/list_node_spec.rb +0 -151
  114. data/spec/unit/orders/ordered_list_spec.rb +0 -335
  115. data/spec/unit/orders/reflection_spec.rb +0 -22
  116. data/spec/unit/pathing_spec.rb +0 -35
  117. data/spec/unit/persistence_spec.rb +0 -115
  118. data/spec/unit/property_predicate_spec.rb +0 -35
  119. data/spec/unit/property_spec.rb +0 -25
  120. data/spec/unit/query_result_builder_spec.rb +0 -31
  121. data/spec/unit/query_spec.rb +0 -307
  122. data/spec/unit/querying_spec.rb +0 -24
  123. data/spec/unit/rdf/indexing_service_spec.rb +0 -114
  124. data/spec/unit/rdf_vocab_spec.rb +0 -30
  125. data/spec/unit/readonly_spec.rb +0 -24
  126. data/spec/unit/reflection_spec.rb +0 -42
  127. data/spec/unit/rspec_matchers/belong_to_associated_active_fedora_object_matcher_spec.rb +0 -37
  128. data/spec/unit/rspec_matchers/have_many_associated_active_fedora_objects_matcher_spec.rb +0 -38
  129. data/spec/unit/rspec_matchers/have_predicate_matcher_spec.rb +0 -38
  130. data/spec/unit/schema_indexing_strategy_spec.rb +0 -68
  131. data/spec/unit/scoping_spec.rb +0 -67
  132. data/spec/unit/serializers_spec.rb +0 -19
  133. data/spec/unit/solr_config_options_spec.rb +0 -57
  134. data/spec/unit/solr_hit_spec.rb +0 -57
  135. data/spec/unit/solr_query_builder_spec.rb +0 -18
  136. data/spec/unit/solr_service_spec.rb +0 -165
  137. data/spec/unit/sparql_insert_spec.rb +0 -31
  138. data/spec/unit/validations_spec.rb +0 -92
  139. data/spec/unit/with_metadata/default_metadata_class_factory_spec.rb +0 -29
  140. data/spec/unit/with_metadata/metadata_node_spec.rb +0 -69
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveFedora::Base do
4
- before(:all) do
5
- class ResurrectionModel < ActiveFedora::Base
6
- after_destroy :eradicate
7
- end
8
- end
9
-
10
- after(:all) do
11
- Object.send(:remove_const, :ResurrectionModel)
12
- end
13
-
14
- context "when an object is has already been deleted" do
15
- let(:ghost) do
16
- obj = described_class.create
17
- obj.destroy
18
- obj.id
19
- end
20
- context "in a typical sitation" do
21
- specify "it cannot be reused" do
22
- expect { described_class.create(id: ghost) }.to raise_error(Ldp::Gone)
23
- end
24
- end
25
- specify "remove its tombstone" do
26
- expect(described_class.eradicate(ghost)).to be true
27
- end
28
- end
29
-
30
- context "when an object has just been deleted" do
31
- let(:zombie) do
32
- obj = described_class.create
33
- obj.destroy
34
- return obj
35
- end
36
- specify "remove its tombstone" do
37
- expect(zombie.eradicate).to be true
38
- end
39
- end
40
-
41
- describe "a model with no tombstones" do
42
- let(:lazarus) do
43
- body = ResurrectionModel.create
44
- soul = body.id
45
- body.destroy
46
- return soul
47
- end
48
- it "allows reusing a uri" do
49
- expect(ResurrectionModel.create(id: lazarus)).to be_kind_of(ResurrectionModel)
50
- end
51
- end
52
- end
@@ -1,30 +0,0 @@
1
- require 'spec_helper'
2
- require 'timeout'
3
-
4
- describe "fedora_solr_sync_issues" do
5
- before :all do
6
- class ParentThing < ActiveFedora::Base
7
- has_many :things, class_name: 'ChildThing', predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
8
- end
9
-
10
- class ChildThing < ActiveFedora::Base
11
- belongs_to :parent, class_name: 'ParentThing', predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
12
- end
13
- end
14
-
15
- after :all do
16
- Object.send(:remove_const, :ChildThing)
17
- Object.send(:remove_const, :ParentThing)
18
- end
19
-
20
- subject(:child) { ChildThing.create parent: parent }
21
- let(:parent) { ParentThing.create }
22
-
23
- before { Ldp::Resource::RdfSource.new(ActiveFedora.fedora.connection, child.uri).delete }
24
-
25
- it "does not go into an infinite loop" do
26
- parent.reload
27
- expect(ActiveFedora::Base.logger).to receive(:error).with("Solr and Fedora may be out of sync:\n")
28
- expect(parent.things).to eq []
29
- end
30
- end
@@ -1,36 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Checking fixity" do
4
- before(:all) do
5
- class MockAFBase < ActiveFedora::Base
6
- has_subresource "data", autocreate: true
7
- end
8
- end
9
-
10
- after(:all) do
11
- Object.send(:remove_const, :MockAFBase)
12
- end
13
-
14
- subject do
15
- obj = MockAFBase.create
16
- obj.data.content = "some content"
17
- obj.save
18
- obj.data.check_fixity
19
- end
20
-
21
- context "with a valid resource" do
22
- it { is_expected.to be true }
23
- end
24
- context "when no uri has been set" do
25
- subject(:file) { ActiveFedora::File.new }
26
- it "raises an error" do
27
- expect { file.check_fixity }.to raise_error(ArgumentError, "You must provide a uri")
28
- end
29
- end
30
- context "with missing resource" do
31
- subject(:file) { ActiveFedora::File.new(ActiveFedora::Base.id_to_uri('123')) }
32
- it "raises an error" do
33
- expect { file.check_fixity }.to raise_error(Ldp::NotFound)
34
- end
35
- end
36
- end
@@ -1,221 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'active_fedora'
4
- require "rexml/document"
5
-
6
- describe ActiveFedora::File do
7
- let(:file) { described_class.new }
8
- describe "#save" do
9
- context "with new files" do
10
- context "with a string" do
11
- before { file.content = "hello" }
12
- it "saves" do
13
- expect(file.save).to be true
14
- end
15
- end
16
-
17
- context "with no content" do
18
- before { file.content = nil }
19
- it "does not save" do
20
- expect(file.save).to be false
21
- end
22
- end
23
- end
24
-
25
- context "with UploadedFile" do
26
- before do
27
- module ActionDispatch
28
- module Http
29
- class UploadedFile
30
- def initialize
31
- @content = StringIO.new("hello world")
32
- end
33
-
34
- def read(a, b)
35
- @content.read(a, b)
36
- end
37
-
38
- def size
39
- @content.length
40
- end
41
- end
42
- end
43
- end
44
- end
45
-
46
- it "saves" do
47
- file.content = ActionDispatch::Http::UploadedFile.new
48
- file.save
49
- expect(file).not_to be_new_record
50
- end
51
- end
52
- end
53
-
54
- context "with a sub-resource that autocreates" do
55
- before do
56
- class MockAFBase < ActiveFedora::Base
57
- has_subresource "descMetadata", class_name: 'SampleResource', autocreate: true
58
- end
59
-
60
- class SampleResource < ActiveFedora::File
61
- def content
62
- 'something to save'
63
- end
64
- end
65
- end
66
-
67
- after do
68
- Object.send(:remove_const, :SampleResource)
69
- Object.send(:remove_const, :MockAFBase)
70
- end
71
-
72
- let(:test_object) { MockAFBase.create }
73
- let(:descMetadata) { test_object.descMetadata }
74
-
75
- describe "changed attributes are set" do
76
- it "marks profile as changed" do
77
- expect_any_instance_of(SampleResource).to receive(:attribute_will_change!).with(:ldp_source)
78
- test_object
79
- end
80
- end
81
-
82
- describe "content_changed? is called" do
83
- before do
84
- allow_any_instance_of(SampleResource).to receive(:content_changed?).and_return(true)
85
- end
86
- subject { descMetadata.described_by }
87
- it { is_expected.to eq descMetadata.uri + '/fcr:metadata' }
88
- end
89
- end
90
-
91
- describe "#content" do
92
- let(:file) { described_class.new { |ds| ds.content = content } }
93
-
94
- before do
95
- file.save
96
- end
97
-
98
- describe "#content" do
99
- subject(:resource) { described_class.new(file.uri).content }
100
-
101
- before { content.rewind }
102
-
103
- context "when encoding is not set" do
104
- let(:content) { fixture('dino.jpg') }
105
-
106
- it "is read from fedora" do
107
- expect(resource).to eq content.read
108
- expect(resource.encoding).to eq Encoding::ASCII_8BIT
109
- end
110
- end
111
-
112
- context "when encoding is set" do
113
- let(:file) do
114
- described_class.new do |f|
115
- f.content = content
116
- f.mime_type = 'text/plain;charset=UTF-8'
117
- end
118
- end
119
- let(:content) { StringIO.new "I'm a little teåpot" }
120
-
121
- it "is read from fedora" do
122
- expect(resource).to eq content.read
123
- expect(resource.encoding).to eq Encoding::UTF_8
124
- end
125
- end
126
- end
127
- end
128
-
129
- context "with a sub-resource" do
130
- before do
131
- class MockAFBase < ActiveFedora::Base
132
- has_subresource "descMetadata", class_name: 'SampleResource'
133
- end
134
-
135
- class SampleResource < ActiveFedora::File
136
- end
137
- end
138
-
139
- after do
140
- Object.send(:remove_const, :SampleResource)
141
- Object.send(:remove_const, :MockAFBase)
142
- end
143
-
144
- let(:test_object) { MockAFBase.create }
145
- let(:descMetadata) { test_object.descMetadata }
146
-
147
- describe "the metadata file" do
148
- subject { descMetadata }
149
- it { is_expected.to be_a_kind_of(described_class) }
150
- end
151
-
152
- context "a binary file" do
153
- let(:path) { "ds#{Time.now.to_i}" }
154
- let(:content) { fixture('dino.jpg') }
155
- let(:file) { described_class.new { |ds| ds.content = content } }
156
-
157
- before do
158
- test_object.attach_file(file, path)
159
- test_object.save
160
- end
161
-
162
- it "is not changed" do
163
- expect(test_object.attached_files[path]).to_not be_content_changed
164
- end
165
-
166
- describe "streaming the response" do
167
- let(:stream_reader) { instance_double(IO) }
168
- it "streams the response" do
169
- expect(stream_reader).to receive(:read).at_least(:once)
170
- test_object.attached_files[path].stream.each { |buff| stream_reader.read(buff) }
171
- end
172
-
173
- context "with a range request" do
174
- before do
175
- test_object.add_file('one1two2threfour', path: 'webm', mime_type: 'video/webm')
176
- test_object.save!
177
- end
178
- subject { str = ''; test_object.webm.stream(range).each { |chunk| str << chunk }; str }
179
- context "whole thing" do
180
- let(:range) { 'bytes=0-15' }
181
- it { is_expected.to eq 'one1two2threfour' }
182
- end
183
- context "open ended" do
184
- let(:range) { 'bytes=0-' }
185
- it { is_expected.to eq 'one1two2threfour' }
186
- end
187
- context "not starting at the beginning" do
188
- let(:range) { 'bytes=3-15' }
189
- it { is_expected.to eq '1two2threfour' }
190
- end
191
- context "not ending at the end" do
192
- let(:range) { 'bytes=4-11' }
193
- it { is_expected.to eq 'two2thre' }
194
- end
195
- end
196
-
197
- context "when the request results in a redirect" do
198
- before do
199
- test_object.add_file('one1two2threfour', path: 'webm', mime_type: 'video/webm')
200
- test_object.add_file('', path: 'redirector', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.webm.uri}\"")
201
- test_object.save!
202
- end
203
- subject { str = ''; test_object.redirector.stream.each { |chunk| str << chunk }; str }
204
- it { is_expected.to eq 'one1two2threfour' }
205
- end
206
-
207
- context "when there are more than 3 requests because of redirects" do
208
- before do
209
- test_object.add_file('', path: 'one', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.attached_files[path].uri}\"")
210
- test_object.add_file('', path: 'two', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.one.uri}\"")
211
- test_object.add_file('', path: 'three', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.two.uri}\"")
212
- test_object.save!
213
- end
214
- it "raises a HTTP redirect too deep Error" do
215
- expect { test_object.three.stream.each { |chunk| chunk } }.to raise_error('HTTP redirect too deep')
216
- end
217
- end
218
- end
219
- end
220
- end
221
- end
@@ -1,26 +0,0 @@
1
- require 'spec_helper'
2
- require 'generators/active_fedora/config/fedora/fedora_generator'
3
-
4
- describe ActiveFedora::Config::FedoraGenerator do
5
- describe "#fcrepo_wrapper_config" do
6
- let(:generator) { described_class.new }
7
- let(:files_to_test) { [
8
- 'config/fcrepo_wrapper_test.yml',
9
- '.fcrepo_wrapper.yml'
10
- ]}
11
-
12
- before do
13
- generator.fcrepo_wrapper_config
14
- end
15
-
16
- after do
17
- files_to_test.each { |file| File.delete(file) if File.exist?(file) }
18
- end
19
-
20
- it "creates config files" do
21
- files_to_test.each do |file|
22
- expect(File).to exist(file), "Expected #{file} to exist"
23
- end
24
- end
25
- end
26
- end
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
- require 'generators/active_fedora/config/solr/solr_generator'
3
-
4
- describe ActiveFedora::Config::SolrGenerator do
5
- describe "#solr_wrapper_config" do
6
- let(:generator) { described_class.new }
7
- let(:files_to_test) { [
8
- 'config/solr_wrapper_test.yml',
9
- '.solr_wrapper.yml'
10
- ]}
11
-
12
- it "creates config files" do
13
- Dir.mktmpdir do |dir|
14
- Dir.chdir(dir) do
15
- generator.solr_wrapper_config
16
- files_to_test.each do |file|
17
- expect(File).to exist(file), "Expected #{file} to exist"
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,41 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveFedora::Base do
4
- before(:all) do
5
- class ResurrectionModel < ActiveFedora::Base
6
- after_destroy :eradicate
7
- end
8
- end
9
-
10
- after(:all) do
11
- Object.send(:remove_const, :ResurrectionModel)
12
- end
13
-
14
- context "when an object is has already been deleted" do
15
- let(:ghost) do
16
- obj = described_class.create
17
- obj.destroy
18
- obj.id
19
- end
20
- it "is gone" do
21
- expect(described_class.gone?(ghost)).to be true
22
- end
23
- end
24
-
25
- context "when the id has never been used" do
26
- let(:id) { "abc123" }
27
- it "is not gone" do
28
- expect(described_class.gone?(id)).to be false
29
- end
30
- end
31
-
32
- context "when the id is in use" do
33
- let(:active) do
34
- obj = described_class.create
35
- obj.id
36
- end
37
- it "is not gone" do
38
- expect(described_class.gone?(active)).to be false
39
- end
40
- end
41
- end
@@ -1,414 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveFedora::Base do
4
- describe "with inverse" do
5
- context "that is also a HABTM" do
6
- before do
7
- class Book < ActiveFedora::Base
8
- has_and_belongs_to_many :topics, predicate: ::RDF::Vocab::FOAF.primaryTopic, inverse_of: :books
9
- end
10
-
11
- class Topic < ActiveFedora::Base
12
- has_and_belongs_to_many :books, predicate: ::RDF::Vocab::FOAF.isPrimaryTopicOf
13
- end
14
- end
15
-
16
- after do
17
- Object.send(:remove_const, :Book)
18
- Object.send(:remove_const, :Topic)
19
- end
20
-
21
- describe "an unsaved instance" do
22
- let(:topic1) { Topic.create }
23
- let(:book) { Book.create }
24
-
25
- it "habtm should set and remove relationships bidirectionally" do
26
- book.topics << topic1
27
- expect(book.topics).to eq [topic1]
28
- expect(topic1.books).to eq [book]
29
- expect(topic1.reload.books).to eq [book]
30
-
31
- book.topics.delete(topic1)
32
- expect(book.topics).to be_empty
33
- expect(topic1.books).to be_empty
34
- end
35
-
36
- it "allows for more than 10 items" do
37
- 12.times do
38
- book.topics << Topic.create
39
- end
40
- book.save
41
- expect(book.topics.count).to eq 12
42
- book2 = Book.find(book.id)
43
- expect(book2.topics.count).to eq 12
44
- end
45
-
46
- context "with subclassed objects" do
47
- before do
48
- class SpecialInheritedBook < Book
49
- end
50
- end
51
-
52
- after do
53
- Object.send(:remove_const, :SpecialInheritedBook)
54
- end
55
-
56
- let!(:special_book) { SpecialInheritedBook.create }
57
- it "finds inherited objects along with base objects" do
58
- book.topics << topic1
59
- special_book.topics << topic1
60
- expect(topic1.books).to match_array [book, special_book]
61
- expect(topic1.reload.books).to match_array [book, special_book]
62
- end
63
- end
64
- end
65
-
66
- describe "a saved instance" do
67
- let!(:book) { Book.create }
68
- let!(:topic1) { Topic.create }
69
- let!(:topic2) { Topic.create }
70
-
71
- it "sets relationships bidirectionally" do
72
- book.topics << topic1
73
- expect(book.topics).to eq [topic1]
74
- expect(book['topic_ids']).to eq [topic1.id]
75
- expect(topic1['book_ids']).to eq [book.id]
76
- expect(Topic.find(topic1.id).books).to eq [book] # Can't have saved it because book isn't saved yet.
77
- end
78
-
79
- it "saves new child objects" do
80
- book.topics << Topic.new
81
- expect(book.topics.first.id).to_not be_nil
82
- end
83
-
84
- it "clears out the old associtions" do
85
- book.topics = [topic1]
86
- book.topics = [topic2]
87
- expect(book.topic_ids).to eq [topic2.id]
88
- end
89
-
90
- context "with members" do
91
- before do
92
- book.topics = [topic1, topic2]
93
- book.save
94
- end
95
-
96
- context "destroy" do
97
- it "removes the associations" do
98
- book.destroy
99
- end
100
- end
101
- end
102
- end
103
- end
104
-
105
- context "that is a has_many" do
106
- before do
107
- class Book < ActiveFedora::Base
108
- has_many :collections
109
- end
110
-
111
- class Collection < ActiveFedora::Base
112
- has_and_belongs_to_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
113
- end
114
- end
115
-
116
- after do
117
- Object.send(:remove_const, :Book)
118
- Object.send(:remove_const, :Collection)
119
- end
120
-
121
- describe "add and remove members" do
122
- let(:collection) { Collection.create }
123
- let(:book) { Book.create }
124
-
125
- it "is successful" do
126
- collection.books << book
127
- expect {
128
- collection.books.delete(book)
129
- }.to change { collection.books.size }.from(1).to(0)
130
- end
131
- end
132
- end
133
- end
134
-
135
- describe "when inverse is not specified" do
136
- before do
137
- class Book < ActiveFedora::Base
138
- has_and_belongs_to_many :collections, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
139
- end
140
-
141
- class Collection < ActiveFedora::Base
142
- has_and_belongs_to_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
143
- end
144
- end
145
-
146
- after do
147
- Object.send(:remove_const, :Book)
148
- Object.send(:remove_const, :Collection)
149
- end
150
-
151
- let(:book) { Book.create }
152
- let(:collection) { Collection.create }
153
-
154
- context "when the book is a member of the collection" do
155
- before do
156
- book.collections << collection
157
- book.save!
158
- end
159
-
160
- it "has a collection" do
161
- expect(book['collection_ids']).to eq [collection.id]
162
- expect(book.collections).to eq [collection]
163
- end
164
- it "habtm should not set foreign relationships if :inverse_of is not specified" do
165
- expect(collection['book_ids']).to be_empty
166
- end
167
- it "loads the collections" do
168
- reloaded = Book.find(book.id)
169
- expect(reloaded.collections).to eq [collection]
170
- end
171
-
172
- describe "#empty?" do
173
- subject { book.collections }
174
- it { is_expected.to_not be_empty }
175
- end
176
- end
177
-
178
- context "when a book isn't in a collection" do
179
- describe "#empty?" do
180
- subject { book.collections }
181
- it { is_expected.to be_empty }
182
- end
183
- end
184
- end
185
-
186
- describe "when destroying the association" do
187
- describe "without callbacks" do
188
- before do
189
- class Book < ActiveFedora::Base
190
- has_and_belongs_to_many :collections, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
191
- end
192
-
193
- class Collection < ActiveFedora::Base
194
- end
195
- end
196
-
197
- after do
198
- Object.send(:remove_const, :Book)
199
- Object.send(:remove_const, :Collection)
200
- end
201
-
202
- let(:book) { Book.create }
203
- let(:collection1) { Collection.create }
204
- let(:collection2) { Collection.create }
205
- before do
206
- book.collections << collection1 << collection2
207
- book.save!
208
- end
209
-
210
- it "delete should cause the entries to be removed from RELS-EXT, but not destroy the original record" do
211
- expect(book.collections).to contain_exactly collection1, collection2
212
- book.collections.delete(collection1)
213
- expect(book.collections).to eq [collection2]
214
- book.save!
215
- book.reload
216
- expect(book.collections).to eq [collection2]
217
- expect(Collection.find(collection1.id)).to_not be_nil
218
- end
219
-
220
- it "destroy should cause the entries to be removed from RELS-EXT, but not destroy the original record" do
221
- expect(book.collections).to contain_exactly collection1, collection2
222
- book.collections.destroy(collection1)
223
- expect(book.collections).to eq [collection2]
224
- book.save!
225
- book.reload
226
- expect(book.collections).to eq [collection2]
227
- expect(Collection.find(collection1.id)).to_not be_nil
228
- end
229
- end
230
-
231
- describe "with remove callbacks" do
232
- before do
233
- class Book < ActiveFedora::Base
234
- has_and_belongs_to_many :collections,
235
- predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection,
236
- before_remove: :foo, after_remove: :bar
237
- end
238
-
239
- class Collection < ActiveFedora::Base
240
- end
241
- end
242
-
243
- after do
244
- Object.send(:remove_const, :Book)
245
- Object.send(:remove_const, :Collection)
246
- end
247
-
248
- let(:book) { Book.create }
249
- let(:collection) { Collection.create }
250
- before do
251
- book.collections << collection
252
- book.save!
253
- end
254
-
255
- it "destroy should cause the before_remove and after_remove callback to be triggered" do
256
- expect(book).to receive(:foo).with(collection)
257
- expect(book).to receive(:bar).with(collection)
258
- book.collections.destroy(collection)
259
- end
260
-
261
- it "delete should cause the before_remove and after_remove callback to be triggered" do
262
- expect(book).to receive(:foo).with(collection)
263
- expect(book).to receive(:bar).with(collection)
264
- book.collections.delete(collection)
265
- end
266
-
267
- it "does not remove if an exception is thrown in before_remove" do
268
- expect(book).to receive(:foo).with(collection).and_raise
269
- expect(book).to_not receive(:bar)
270
- begin
271
- book.collections.delete(collection)
272
- rescue RuntimeError
273
- end
274
- expect(book.collections).to eq [collection]
275
- end
276
- end
277
-
278
- describe "with add callbacks" do
279
- before do
280
- class Book < ActiveFedora::Base
281
- has_and_belongs_to_many :collections,
282
- predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection,
283
- before_add: :foo, after_add: :bar
284
- end
285
-
286
- class Collection < ActiveFedora::Base
287
- end
288
- end
289
-
290
- after do
291
- Object.send(:remove_const, :Book)
292
- Object.send(:remove_const, :Collection)
293
- end
294
-
295
- let(:book) { Book.create }
296
- let(:collection) { Collection.create }
297
-
298
- it "shift should cause the before_add and after_add callback to be triggered" do
299
- expect(book).to receive(:foo).with(collection)
300
- expect(book).to receive(:bar).with(collection)
301
- book.collections << collection
302
- end
303
-
304
- it "assignment should cause the before_add and after_add callback to be triggered" do
305
- expect(book).to receive(:foo).with(collection)
306
- expect(book).to receive(:bar).with(collection)
307
- book.collections = [collection]
308
- end
309
-
310
- it "does not add if an exception is thrown in before_add" do
311
- expect(book).to receive(:foo).with(collection).and_raise
312
- expect(book).to_not receive(:bar)
313
- begin
314
- book.collections << collection
315
- rescue RuntimeError
316
- end
317
- expect(book.collections).to eq []
318
- end
319
- end
320
- end
321
-
322
- describe "create" do
323
- before do
324
- class Book < ActiveFedora::Base
325
- has_and_belongs_to_many :collections, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
326
- end
327
-
328
- class Collection < ActiveFedora::Base
329
- property :title, predicate: ::RDF::Vocab::DC.title
330
- end
331
- end
332
-
333
- after do
334
- Object.send(:remove_const, :Book)
335
- Object.send(:remove_const, :Collection)
336
- end
337
-
338
- let(:book) { Book.create }
339
-
340
- it "creates" do
341
- collection = book.collections.create(title: ["Permanent"])
342
- expect(collection).to be_kind_of Collection
343
- expect(book.collections).to include collection
344
- book.save
345
- expect(book.reload.collections.first.title).to eq ['Permanent']
346
- end
347
- end
348
-
349
- describe "Autosave" do
350
- before do
351
- class Item < ActiveFedora::Base
352
- has_many :components
353
- property :title, predicate: ::RDF::Vocab::DC.title
354
- end
355
-
356
- class Component < ActiveFedora::Base
357
- has_and_belongs_to_many :items, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
358
- property :description, predicate: ::RDF::Vocab::DC.description
359
- end
360
- end
361
-
362
- after do
363
- Object.send(:remove_const, :Item)
364
- Object.send(:remove_const, :Component)
365
- end
366
-
367
- describe "From the has_and_belongs_to_many side" do
368
- describe "dependent records" do
369
- let(:component) { Component.create(items: [Item.new(title: ['my title'])]) }
370
-
371
- it "is saved" do
372
- component.reload
373
- expect(component.items.first.title).to eq ['my title']
374
- end
375
- end
376
-
377
- describe "shifting" do
378
- let(:component) { Component.new }
379
- let(:item) { Item.create }
380
-
381
- it "sets item_ids" do
382
- component.items << item
383
- expect(component.item_ids).to eq [item.id]
384
- end
385
- end
386
-
387
- context "when the has_and_belongs_to_many provides an inverse_of" do
388
- let(:reflection) { Component._reflect_on_association(:items) }
389
- before do
390
- reflection.options[:inverse_of] = :components
391
- end
392
-
393
- describe "shifting" do
394
- let(:component) { Component.create }
395
- let(:item) { Item.new }
396
-
397
- it "sets item_ids" do
398
- component.items << item
399
- expect(component.item_ids).to eq [item.id]
400
- end
401
- end
402
- end
403
- end
404
-
405
- describe "From the has_many side" do
406
- let(:item) { Item.create(components: [Component.new(description: ['my description'])]) }
407
-
408
- it "saves dependent records" do
409
- item.reload
410
- expect(item.components.first.description).to eq ['my description']
411
- end
412
- end
413
- end
414
- end