active-fedora 6.8.0 → 7.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (215) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +15 -5
  4. data/CONTRIBUTING.md +2 -0
  5. data/Gemfile +0 -2
  6. data/History.txt +2 -32
  7. data/README.md +143 -0
  8. data/Rakefile +5 -7
  9. data/active-fedora.gemspec +9 -9
  10. data/gemfiles/rails3.gemfile +11 -0
  11. data/gemfiles/rails4.gemfile +10 -0
  12. data/lib/active_fedora.rb +31 -4
  13. data/lib/active_fedora/association_relation.rb +18 -0
  14. data/lib/active_fedora/associations.rb +38 -171
  15. data/lib/active_fedora/associations/association.rb +163 -0
  16. data/lib/active_fedora/associations/association_scope.rb +39 -0
  17. data/lib/active_fedora/associations/belongs_to_association.rb +47 -25
  18. data/lib/active_fedora/associations/builder/association.rb +55 -0
  19. data/lib/active_fedora/associations/builder/belongs_to.rb +100 -0
  20. data/lib/active_fedora/associations/builder/collection_association.rb +56 -0
  21. data/lib/active_fedora/associations/builder/has_and_belongs_to_many.rb +30 -0
  22. data/lib/active_fedora/associations/builder/has_many.rb +63 -0
  23. data/lib/active_fedora/associations/builder/singular_association.rb +32 -0
  24. data/lib/active_fedora/associations/{association_collection.rb → collection_association.rb} +203 -53
  25. data/lib/active_fedora/associations/collection_proxy.rb +862 -0
  26. data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +35 -25
  27. data/lib/active_fedora/associations/has_many_association.rb +36 -11
  28. data/lib/active_fedora/associations/singular_association.rb +62 -0
  29. data/lib/active_fedora/attributes.rb +43 -139
  30. data/lib/active_fedora/autosave_association.rb +317 -0
  31. data/lib/active_fedora/base.rb +10 -327
  32. data/lib/active_fedora/callbacks.rb +1 -3
  33. data/lib/active_fedora/content_model.rb +16 -0
  34. data/lib/active_fedora/core.rb +151 -0
  35. data/lib/active_fedora/datastream_attribute.rb +76 -0
  36. data/lib/active_fedora/datastream_hash.rb +8 -13
  37. data/lib/active_fedora/datastreams.rb +39 -26
  38. data/lib/active_fedora/digital_object.rb +2 -2
  39. data/lib/active_fedora/fedora_attributes.rb +45 -0
  40. data/lib/active_fedora/fixture_loader.rb +1 -1
  41. data/lib/active_fedora/indexing.rb +6 -1
  42. data/lib/active_fedora/model.rb +0 -17
  43. data/lib/active_fedora/nested_attributes.rb +2 -2
  44. data/lib/active_fedora/null_relation.rb +7 -0
  45. data/lib/active_fedora/om_datastream.rb +3 -4
  46. data/lib/active_fedora/persistence.rb +41 -29
  47. data/lib/active_fedora/querying.rb +2 -163
  48. data/lib/active_fedora/rdf.rb +1 -0
  49. data/lib/active_fedora/rdf/indexing.rb +67 -0
  50. data/lib/active_fedora/rdf_datastream.rb +2 -50
  51. data/lib/active_fedora/rdf_node.rb +12 -7
  52. data/lib/active_fedora/rdf_node/term_proxy.rb +30 -21
  53. data/lib/active_fedora/rdfxml_rdf_datastream.rb +1 -1
  54. data/lib/active_fedora/reflection.rb +163 -20
  55. data/lib/active_fedora/relation.rb +33 -130
  56. data/lib/active_fedora/relation/calculations.rb +19 -0
  57. data/lib/active_fedora/relation/delegation.rb +22 -0
  58. data/lib/active_fedora/relation/finder_methods.rb +247 -0
  59. data/lib/active_fedora/relation/merger.rb +22 -0
  60. data/lib/active_fedora/relation/query_methods.rb +58 -0
  61. data/lib/active_fedora/relation/spawn_methods.rb +46 -0
  62. data/lib/active_fedora/relationship_graph.rb +0 -2
  63. data/lib/active_fedora/rels_ext_datastream.rb +1 -4
  64. data/lib/active_fedora/rubydora_connection.rb +1 -1
  65. data/lib/active_fedora/scoping.rb +20 -0
  66. data/lib/active_fedora/scoping/default.rb +38 -0
  67. data/lib/active_fedora/scoping/named.rb +32 -0
  68. data/lib/active_fedora/semantic_node.rb +54 -106
  69. data/lib/active_fedora/serialization.rb +19 -0
  70. data/lib/active_fedora/sharding.rb +58 -0
  71. data/lib/active_fedora/solr_digital_object.rb +15 -5
  72. data/lib/active_fedora/solr_instance_loader.rb +1 -1
  73. data/lib/active_fedora/solr_service.rb +1 -1
  74. data/lib/active_fedora/unsaved_digital_object.rb +6 -4
  75. data/lib/active_fedora/version.rb +1 -1
  76. data/lib/tasks/active_fedora.rake +3 -0
  77. data/lib/tasks/active_fedora_dev.rake +6 -5
  78. data/spec/config_helper.rb +14 -14
  79. data/spec/integration/associations_spec.rb +168 -455
  80. data/spec/integration/attributes_spec.rb +12 -11
  81. data/spec/integration/auditable_spec.rb +11 -11
  82. data/spec/integration/autosave_association_spec.rb +25 -0
  83. data/spec/integration/base_spec.rb +163 -163
  84. data/spec/integration/belongs_to_association_spec.rb +166 -0
  85. data/spec/integration/bug_spec.rb +7 -7
  86. data/spec/integration/collection_association_spec.rb +58 -0
  87. data/spec/integration/complex_rdf_datastream_spec.rb +88 -88
  88. data/spec/integration/datastream_collections_spec.rb +69 -69
  89. data/spec/integration/datastream_spec.rb +43 -43
  90. data/spec/integration/datastreams_spec.rb +63 -63
  91. data/spec/integration/delete_all_spec.rb +46 -39
  92. data/spec/integration/fedora_solr_sync_spec.rb +5 -5
  93. data/spec/integration/field_to_solr_name_spec.rb +34 -0
  94. data/spec/integration/full_featured_model_spec.rb +100 -101
  95. data/spec/integration/has_and_belongs_to_many_associations_spec.rb +341 -0
  96. data/spec/integration/has_many_associations_spec.rb +172 -24
  97. data/spec/integration/json_serialization_spec.rb +31 -0
  98. data/spec/integration/load_from_solr_spec.rb +48 -0
  99. data/spec/integration/model_spec.rb +35 -40
  100. data/spec/integration/nested_attribute_spec.rb +42 -43
  101. data/spec/integration/ntriples_datastream_spec.rb +131 -113
  102. data/spec/integration/om_datastream_spec.rb +67 -67
  103. data/spec/integration/persistence_spec.rb +7 -7
  104. data/spec/integration/rdf_nested_attributes_spec.rb +56 -56
  105. data/spec/integration/relation_delegation_spec.rb +26 -25
  106. data/spec/integration/relation_spec.rb +42 -0
  107. data/spec/integration/rels_ext_datastream_spec.rb +20 -20
  108. data/spec/integration/scoped_query_spec.rb +61 -51
  109. data/spec/integration/solr_instance_loader_spec.rb +5 -5
  110. data/spec/integration/solr_service_spec.rb +46 -46
  111. data/spec/samples/hydra-mods_article_datastream.rb +334 -334
  112. data/spec/samples/hydra-rights_metadata_datastream.rb +57 -57
  113. data/spec/samples/marpa-dc_datastream.rb +17 -17
  114. data/spec/samples/models/audio_record.rb +16 -16
  115. data/spec/samples/models/image.rb +2 -2
  116. data/spec/samples/models/mods_article.rb +5 -5
  117. data/spec/samples/models/oral_history.rb +18 -18
  118. data/spec/samples/models/seminar.rb +24 -24
  119. data/spec/samples/models/seminar_audio_file.rb +17 -17
  120. data/spec/samples/oral_history_sample_model.rb +21 -21
  121. data/spec/samples/special_thing.rb +14 -14
  122. data/spec/spec_helper.rb +11 -7
  123. data/spec/support/an_active_model.rb +2 -8
  124. data/spec/support/freeze_mocks.rb +12 -0
  125. data/spec/support/mock_fedora.rb +17 -16
  126. data/spec/unit/active_fedora_spec.rb +58 -60
  127. data/spec/unit/attributes_spec.rb +314 -0
  128. data/spec/unit/base_active_model_spec.rb +28 -27
  129. data/spec/unit/base_cma_spec.rb +5 -5
  130. data/spec/unit/base_datastream_management_spec.rb +27 -27
  131. data/spec/unit/base_extra_spec.rb +76 -48
  132. data/spec/unit/base_spec.rb +277 -348
  133. data/spec/unit/callback_spec.rb +18 -19
  134. data/spec/unit/code_configurator_spec.rb +17 -17
  135. data/spec/unit/config_spec.rb +8 -16
  136. data/spec/unit/content_model_spec.rb +79 -60
  137. data/spec/unit/datastream_collections_spec.rb +229 -229
  138. data/spec/unit/datastream_spec.rb +51 -63
  139. data/spec/unit/datastreams_spec.rb +87 -87
  140. data/spec/unit/file_configurator_spec.rb +217 -217
  141. data/spec/unit/has_and_belongs_to_many_collection_spec.rb +44 -25
  142. data/spec/unit/has_many_collection_spec.rb +26 -8
  143. data/spec/unit/inheritance_spec.rb +13 -12
  144. data/spec/unit/model_spec.rb +39 -45
  145. data/spec/unit/nom_datastream_spec.rb +15 -15
  146. data/spec/unit/ntriples_datastream_spec.rb +123 -118
  147. data/spec/unit/om_datastream_spec.rb +227 -233
  148. data/spec/unit/persistence_spec.rb +34 -15
  149. data/spec/unit/predicates_spec.rb +73 -73
  150. data/spec/unit/property_spec.rb +17 -9
  151. data/spec/unit/qualified_dublin_core_datastream_spec.rb +33 -33
  152. data/spec/unit/query_spec.rb +222 -198
  153. data/spec/unit/rdf_datastream_spec.rb +21 -28
  154. data/spec/unit/rdf_list_nested_attributes_spec.rb +34 -34
  155. data/spec/unit/rdf_list_spec.rb +65 -64
  156. data/spec/unit/rdf_node_spec.rb +7 -7
  157. data/spec/unit/rdf_xml_writer_spec.rb +10 -10
  158. data/spec/unit/rdfxml_rdf_datastream_spec.rb +27 -27
  159. data/spec/unit/relationship_graph_spec.rb +51 -51
  160. data/spec/unit/rels_ext_datastream_spec.rb +68 -74
  161. data/spec/unit/rspec_matchers/belong_to_associated_active_fedora_object_matcher_spec.rb +15 -15
  162. data/spec/unit/rspec_matchers/have_many_associated_active_fedora_objects_matcher_spec.rb +15 -15
  163. data/spec/unit/rspec_matchers/have_predicate_matcher_spec.rb +15 -15
  164. data/spec/unit/rspec_matchers/match_fedora_datastream_matcher_spec.rb +12 -12
  165. data/spec/unit/rubydora_connection_spec.rb +5 -5
  166. data/spec/unit/semantic_node_spec.rb +48 -107
  167. data/spec/unit/serializers_spec.rb +4 -4
  168. data/spec/unit/service_definitions_spec.rb +26 -26
  169. data/spec/unit/simple_datastream_spec.rb +17 -17
  170. data/spec/unit/solr_config_options_spec.rb +29 -28
  171. data/spec/unit/solr_digital_object_spec.rb +17 -25
  172. data/spec/unit/solr_service_spec.rb +95 -82
  173. data/spec/unit/unsaved_digital_object_spec.rb +24 -23
  174. data/spec/unit/validations_spec.rb +21 -21
  175. metadata +110 -159
  176. data/.rspec +0 -1
  177. data/.rubocop.yml +0 -1
  178. data/.rubocop_todo.yml +0 -938
  179. data/CONSOLE_GETTING_STARTED.textile +0 -1
  180. data/NOKOGIRI_DATASTREAMS.textile +0 -1
  181. data/README.textile +0 -116
  182. data/lib/active_fedora/associations/association_proxy.rb +0 -178
  183. data/lib/active_fedora/delegating.rb +0 -72
  184. data/lib/active_fedora/nokogiri_datastream.rb +0 -11
  185. data/spec/integration/delegating_spec.rb +0 -59
  186. data/spec/rails3_test_app/.gitignore +0 -4
  187. data/spec/rails3_test_app/.rspec +0 -1
  188. data/spec/rails3_test_app/Gemfile +0 -40
  189. data/spec/rails3_test_app/Rakefile +0 -7
  190. data/spec/rails3_test_app/app/controllers/application_controller.rb +0 -3
  191. data/spec/rails3_test_app/app/helpers/application_helper.rb +0 -2
  192. data/spec/rails3_test_app/app/views/layouts/application.html.erb +0 -14
  193. data/spec/rails3_test_app/config.ru +0 -4
  194. data/spec/rails3_test_app/config/application.rb +0 -42
  195. data/spec/rails3_test_app/config/boot.rb +0 -6
  196. data/spec/rails3_test_app/config/database.yml +0 -22
  197. data/spec/rails3_test_app/config/environment.rb +0 -5
  198. data/spec/rails3_test_app/config/environments/development.rb +0 -25
  199. data/spec/rails3_test_app/config/environments/production.rb +0 -49
  200. data/spec/rails3_test_app/config/environments/test.rb +0 -35
  201. data/spec/rails3_test_app/config/initializers/backtrace_silencers.rb +0 -7
  202. data/spec/rails3_test_app/config/initializers/inflections.rb +0 -10
  203. data/spec/rails3_test_app/config/initializers/mime_types.rb +0 -5
  204. data/spec/rails3_test_app/config/initializers/secret_token.rb +0 -7
  205. data/spec/rails3_test_app/config/initializers/session_store.rb +0 -8
  206. data/spec/rails3_test_app/config/locales/en.yml +0 -5
  207. data/spec/rails3_test_app/config/routes.rb +0 -58
  208. data/spec/rails3_test_app/db/seeds.rb +0 -7
  209. data/spec/rails3_test_app/run_tests +0 -3
  210. data/spec/rails3_test_app/script/rails +0 -6
  211. data/spec/rails3_test_app/spec/spec_helper.rb +0 -27
  212. data/spec/rails3_test_app/spec/unit/rails_3_init.rb +0 -15
  213. data/spec/unit/association_proxy_spec.rb +0 -12
  214. data/spec/unit/base_delegate_spec.rb +0 -197
  215. data/spec/unit/base_delegate_to_spec.rb +0 -73
@@ -0,0 +1,862 @@
1
+ module ActiveFedora
2
+ module Associations
3
+ # Association proxies in Active Fedora are middlemen between the object that
4
+ # holds the association, known as the <tt>@owner</tt>, and the actual associated
5
+ # object, known as the <tt>@target</tt>. The kind of association any proxy is
6
+ # about is available in <tt>@reflection</tt>. That's an instance of the class
7
+ # ActiveFedora::Reflection::AssociationReflection.
8
+ #
9
+ # For example, given
10
+ #
11
+ # class Blog < ActiveFedora::Base
12
+ # has_many :posts
13
+ # end
14
+ #
15
+ # blog = Blog.find(:first)
16
+ #
17
+ # the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
18
+ # <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
19
+ # the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
20
+ #
21
+ # This class has most of the basic instance methods removed, and delegates
22
+ # unknown methods to <tt>@target</tt> via <tt>method_missing</tt>. As a
23
+ # corner case, it even removes the +class+ method and that's why you get
24
+ #
25
+ # blog.posts.class # => Array
26
+ #
27
+ # though the object behind <tt>blog.posts</tt> is not an Array, but an
28
+ # ActiveFedora::Associations::HasManyAssociation.
29
+ #
30
+ # The <tt>@target</tt> object is not \loaded until needed. For example,
31
+ #
32
+ # blog.posts.count
33
+ #
34
+ # is computed directly through Solr and does not trigger by itself the
35
+ # instantiation of the actual post records.
36
+ class CollectionProxy < Relation # :nodoc:
37
+
38
+ def initialize(association)
39
+ @association = association
40
+ super association.klass
41
+ merge! association.scope
42
+ end
43
+
44
+ def target
45
+ @association.target
46
+ end
47
+
48
+ def load_target
49
+ @association.load_target
50
+ end
51
+
52
+ def loaded?
53
+ @association.loaded?
54
+ end
55
+
56
+ # Works in two ways.
57
+ #
58
+ # *First:* Specify a subset of fields to be selected from the result set.
59
+ #
60
+ # class Person < ActiveFedora::Base
61
+ # has_many :pets
62
+ # end
63
+ #
64
+ # person.pets
65
+ # # => [
66
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
67
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
68
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
69
+ # # ]
70
+ #
71
+ # person.pets.select(:name)
72
+ # # => [
73
+ # # #<Pet id: nil, name: "Fancy-Fancy">,
74
+ # # #<Pet id: nil, name: "Spook">,
75
+ # # #<Pet id: nil, name: "Choo-Choo">
76
+ # # ]
77
+ #
78
+ # person.pets.select([:id, :name])
79
+ # # => [
80
+ # # #<Pet id: 1, name: "Fancy-Fancy">,
81
+ # # #<Pet id: 2, name: "Spook">,
82
+ # # #<Pet id: 3, name: "Choo-Choo">
83
+ # # ]
84
+ #
85
+ # Be careful because this also means you’re initializing a model
86
+ # object with only the fields that you’ve selected. If you attempt
87
+ # to access a field that is not in the initialized record you’ll
88
+ # receive:
89
+ #
90
+ # person.pets.select(:name).first.person_id
91
+ # # => ActiveModel::MissingAttributeError: missing attribute: person_id
92
+ #
93
+ # *Second:* You can pass a block so it can be used just like Array#select.
94
+ # This build an array of objects from the database for the scope,
95
+ # converting them into an array and iterating through them using
96
+ # Array#select.
97
+ #
98
+ # person.pets.select { |pet| pet.name =~ /oo/ }
99
+ # # => [
100
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
101
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
102
+ # # ]
103
+ #
104
+ # person.pets.select(:name) { |pet| pet.name =~ /oo/ }
105
+ # # => [
106
+ # # #<Pet id: 2, name: "Spook">,
107
+ # # #<Pet id: 3, name: "Choo-Choo">
108
+ # # ]
109
+ def select(select = nil, &block)
110
+ @association.select(select, &block)
111
+ end
112
+
113
+ # Finds an object in the collection responding to the +id+. Uses the same
114
+ # rules as <tt>ActiveFedora::Base.find</tt>. Returns <tt>ActiveFedora::RecordNotFound</tt>
115
+ # error if the object can not be found.
116
+ #
117
+ # class Person < ActiveFedora::Base
118
+ # has_many :pets
119
+ # end
120
+ #
121
+ # person.pets
122
+ # # => [
123
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
124
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
125
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
126
+ # # ]
127
+ #
128
+ # person.pets.find(1) # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
129
+ # person.pets.find(4) # => ActiveFedora::RecordNotFound: Couldn't find Pet with id=4
130
+ #
131
+ # person.pets.find(2) { |pet| pet.name.downcase! }
132
+ # # => #<Pet id: 2, name: "fancy-fancy", person_id: 1>
133
+ #
134
+ # person.pets.find(2, 3)
135
+ # # => [
136
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
137
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
138
+ # # ]
139
+ def find(*args, &block)
140
+ @association.find(*args, &block)
141
+ end
142
+
143
+ # Returns the first record, or the first +n+ records, from the collection.
144
+ # If the collection is empty, the first form returns +nil+, and the second
145
+ # form returns an empty array.
146
+ #
147
+ # class Person < ActiveFedora::Base
148
+ # has_many :pets
149
+ # end
150
+ #
151
+ # person.pets
152
+ # # => [
153
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
154
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
155
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
156
+ # # ]
157
+ #
158
+ # person.pets.first # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
159
+ #
160
+ # person.pets.first(2)
161
+ # # => [
162
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
163
+ # # #<Pet id: 2, name: "Spook", person_id: 1>
164
+ # # ]
165
+ #
166
+ # another_person_without.pets # => []
167
+ # another_person_without.pets.first # => nil
168
+ # another_person_without.pets.first(3) # => []
169
+ def first(*args)
170
+ @association.first(*args)
171
+ end
172
+
173
+ # Returns the last record, or the last +n+ records, from the collection.
174
+ # If the collection is empty, the first form returns +nil+, and the second
175
+ # form returns an empty array.
176
+ #
177
+ # class Person < ActiveFedora::Base
178
+ # has_many :pets
179
+ # end
180
+ #
181
+ # person.pets
182
+ # # => [
183
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
184
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
185
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
186
+ # # ]
187
+ #
188
+ # person.pets.last # => #<Pet id: 3, name: "Choo-Choo", person_id: 1>
189
+ #
190
+ # person.pets.last(2)
191
+ # # => [
192
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
193
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
194
+ # # ]
195
+ #
196
+ # another_person_without.pets # => []
197
+ # another_person_without.pets.last # => nil
198
+ # another_person_without.pets.last(3) # => []
199
+ def last(*args)
200
+ @association.last(*args)
201
+ end
202
+
203
+ # Returns a new object of the collection type that has been instantiated
204
+ # with +attributes+ and linked to this object, but have not yet been saved.
205
+ # You can pass an array of attributes hashes, this will return an array
206
+ # with the new objects.
207
+ #
208
+ # class Person
209
+ # has_many :pets
210
+ # end
211
+ #
212
+ # person.pets.build
213
+ # # => #<Pet id: nil, name: nil, person_id: 1>
214
+ #
215
+ # person.pets.build(name: 'Fancy-Fancy')
216
+ # # => #<Pet id: nil, name: "Fancy-Fancy", person_id: 1>
217
+ #
218
+ # person.pets.build([{name: 'Spook'}, {name: 'Choo-Choo'}, {name: 'Brain'}])
219
+ # # => [
220
+ # # #<Pet id: nil, name: "Spook", person_id: 1>,
221
+ # # #<Pet id: nil, name: "Choo-Choo", person_id: 1>,
222
+ # # #<Pet id: nil, name: "Brain", person_id: 1>
223
+ # # ]
224
+ #
225
+ # person.pets.size # => 5 # size of the collection
226
+ # person.pets.count # => 0 # count from database
227
+ def build(attributes = {}, &block)
228
+ @association.build(attributes, &block)
229
+ end
230
+
231
+ # Returns a new object of the collection type that has been instantiated with
232
+ # attributes, linked to this object and that has already been saved (if it
233
+ # passes the validations).
234
+ #
235
+ # class Person
236
+ # has_many :pets
237
+ # end
238
+ #
239
+ # person.pets.create(name: 'Fancy-Fancy')
240
+ # # => #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>
241
+ #
242
+ # person.pets.create([{name: 'Spook'}, {name: 'Choo-Choo'}])
243
+ # # => [
244
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
245
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
246
+ # # ]
247
+ #
248
+ # person.pets.size # => 3
249
+ # person.pets.count # => 3
250
+ #
251
+ # person.pets.find(1, 2, 3)
252
+ # # => [
253
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
254
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
255
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
256
+ # # ]
257
+ def create(attributes = {}, &block)
258
+ @association.create(attributes, &block)
259
+ end
260
+
261
+ # Like +create+, except that if the record is invalid, raises an exception.
262
+ #
263
+ # class Person
264
+ # has_many :pets
265
+ # end
266
+ #
267
+ # class Pet
268
+ # validates :name, presence: true
269
+ # end
270
+ #
271
+ # person.pets.create!(name: nil)
272
+ # # => ActiveFedora::RecordInvalid: Validation failed: Name can't be blank
273
+ def create!(attributes = {}, &block)
274
+ @association.create!(attributes, &block)
275
+ end
276
+
277
+ # Add one or more records to the collection by setting their foreign keys
278
+ # to the association's primary key. Since << flattens its argument list and
279
+ # inserts each record, +push+ and +concat+ behave identically. Returns +self+
280
+ # so method calls may be chained.
281
+ #
282
+ # class Person < ActiveFedora::Base
283
+ # pets :has_many
284
+ # end
285
+ #
286
+ # person.pets.size # => 0
287
+ # person.pets.concat(Pet.new(name: 'Fancy-Fancy'))
288
+ # person.pets.concat(Pet.new(name: 'Spook'), Pet.new(name: 'Choo-Choo'))
289
+ # person.pets.size # => 3
290
+ #
291
+ # person.id # => 1
292
+ # person.pets
293
+ # # => [
294
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
295
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
296
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
297
+ # # ]
298
+ #
299
+ # person.pets.concat([Pet.new(name: 'Brain'), Pet.new(name: 'Benny')])
300
+ # person.pets.size # => 5
301
+ def concat(*records)
302
+ @association.concat(*records)
303
+ end
304
+
305
+ # Replace this collection with +other_array+. This will perform a diff
306
+ # and delete/add only records that have changed.
307
+ #
308
+ # class Person < ActiveFedora::Base
309
+ # has_many :pets
310
+ # end
311
+ #
312
+ # person.pets
313
+ # # => [#<Pet id: 1, name: "Gorby", group: "cats", person_id: 1>]
314
+ #
315
+ # other_pets = [Pet.new(name: 'Puff', group: 'celebrities']
316
+ #
317
+ # person.pets.replace(other_pets)
318
+ #
319
+ # person.pets
320
+ # # => [#<Pet id: 2, name: "Puff", group: "celebrities", person_id: 1>]
321
+ #
322
+ # If the supplied array has an incorrect association type, it raises
323
+ # an <tt>ActiveFedora::AssociationTypeMismatch</tt> error:
324
+ #
325
+ # person.pets.replace(["doo", "ggie", "gaga"])
326
+ # # => ActiveFedora::AssociationTypeMismatch: Pet expected, got String
327
+ def replace(other_array)
328
+ @association.replace(other_array)
329
+ end
330
+
331
+ # Deletes all the records from the collection. For +has_many+ associations,
332
+ # the deletion is done according to the strategy specified by the <tt>:dependent</tt>
333
+ # option. Returns an array with the deleted records.
334
+ #
335
+ # If no <tt>:dependent</tt> option is given, then it will follow the
336
+ # default strategy. The default strategy is <tt>:nullify</tt>. This
337
+ # sets the foreign keys to <tt>NULL</tt>. For, +has_many+ <tt>:through</tt>,
338
+ # the default strategy is +delete_all+.
339
+ #
340
+ # class Person < ActiveFedora::Base
341
+ # has_many :pets # dependent: :nullify option by default
342
+ # end
343
+ #
344
+ # person.pets.size # => 3
345
+ # person.pets
346
+ # # => [
347
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
348
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
349
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
350
+ # # ]
351
+ #
352
+ # person.pets.delete_all
353
+ # # => [
354
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
355
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
356
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
357
+ # # ]
358
+ #
359
+ # person.pets.size # => 0
360
+ # person.pets # => []
361
+ #
362
+ # Pet.find(1, 2, 3)
363
+ # # => [
364
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: nil>,
365
+ # # #<Pet id: 2, name: "Spook", person_id: nil>,
366
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: nil>
367
+ # # ]
368
+ #
369
+ # If it is set to <tt>:destroy</tt> all the objects from the collection
370
+ # are removed by calling their +destroy+ method. See +destroy+ for more
371
+ # information.
372
+ #
373
+ # class Person < ActiveFedora::Base
374
+ # has_many :pets, dependent: :destroy
375
+ # end
376
+ #
377
+ # person.pets.size # => 3
378
+ # person.pets
379
+ # # => [
380
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
381
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
382
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
383
+ # # ]
384
+ #
385
+ # person.pets.delete_all
386
+ # # => [
387
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
388
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
389
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
390
+ # # ]
391
+ #
392
+ # Pet.find(1, 2, 3)
393
+ # # => ActiveFedora::RecordNotFound
394
+ #
395
+ # If it is set to <tt>:delete_all</tt>, all the objects are deleted
396
+ # *without* calling their +destroy+ method.
397
+ #
398
+ # class Person < ActiveFedora::Base
399
+ # has_many :pets, dependent: :delete_all
400
+ # end
401
+ #
402
+ # person.pets.size # => 3
403
+ # person.pets
404
+ # # => [
405
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
406
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
407
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
408
+ # # ]
409
+ #
410
+ # person.pets.delete_all
411
+ # # => [
412
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
413
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
414
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
415
+ # # ]
416
+ #
417
+ # Pet.find(1, 2, 3)
418
+ # # => ActiveFedora::RecordNotFound
419
+ def delete_all
420
+ @association.delete_all
421
+ end
422
+
423
+ # Deletes the records of the collection directly from the database.
424
+ # This will _always_ remove the records ignoring the +:dependent+
425
+ # option.
426
+ #
427
+ # class Person < ActiveFedora::Base
428
+ # has_many :pets
429
+ # end
430
+ #
431
+ # person.pets.size # => 3
432
+ # person.pets
433
+ # # => [
434
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
435
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
436
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
437
+ # # ]
438
+ #
439
+ # person.pets.destroy_all
440
+ #
441
+ # person.pets.size # => 0
442
+ # person.pets # => []
443
+ #
444
+ # Pet.find(1) # => Couldn't find Pet with id=1
445
+ def destroy_all
446
+ @association.destroy_all
447
+ end
448
+
449
+ # Deletes the +records+ supplied and removes them from the collection. For
450
+ # +has_many+ associations, the deletion is done according to the strategy
451
+ # specified by the <tt>:dependent</tt> option. Returns an array with the
452
+ # deleted records.
453
+ #
454
+ # If no <tt>:dependent</tt> option is given, then it will follow the default
455
+ # strategy. The default strategy is <tt>:nullify</tt>. This sets the foreign
456
+ # keys to <tt>NULL</tt>. For, +has_many+ <tt>:through</tt>, the default
457
+ # strategy is +delete_all+.
458
+ #
459
+ # class Person < ActiveFedora::Base
460
+ # has_many :pets # dependent: :nullify option by default
461
+ # end
462
+ #
463
+ # person.pets.size # => 3
464
+ # person.pets
465
+ # # => [
466
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
467
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
468
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
469
+ # # ]
470
+ #
471
+ # person.pets.delete(Pet.find(1))
472
+ # # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
473
+ #
474
+ # person.pets.size # => 2
475
+ # person.pets
476
+ # # => [
477
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
478
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
479
+ # # ]
480
+ #
481
+ # Pet.find(1)
482
+ # # => #<Pet id: 1, name: "Fancy-Fancy", person_id: nil>
483
+ #
484
+ # If it is set to <tt>:destroy</tt> all the +records+ are removed by calling
485
+ # their +destroy+ method. See +destroy+ for more information.
486
+ #
487
+ # class Person < ActiveFedora::Base
488
+ # has_many :pets, dependent: :destroy
489
+ # end
490
+ #
491
+ # person.pets.size # => 3
492
+ # person.pets
493
+ # # => [
494
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
495
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
496
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
497
+ # # ]
498
+ #
499
+ # person.pets.delete(Pet.find(1), Pet.find(3))
500
+ # # => [
501
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
502
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
503
+ # # ]
504
+ #
505
+ # person.pets.size # => 1
506
+ # person.pets
507
+ # # => [#<Pet id: 2, name: "Spook", person_id: 1>]
508
+ #
509
+ # Pet.find(1, 3)
510
+ # # => ActiveFedora::RecordNotFound: Couldn't find all Pets with IDs (1, 3)
511
+ #
512
+ # If it is set to <tt>:delete_all</tt>, all the +records+ are deleted
513
+ # *without* calling their +destroy+ method.
514
+ #
515
+ # class Person < ActiveFedora::Base
516
+ # has_many :pets, dependent: :delete_all
517
+ # end
518
+ #
519
+ # person.pets.size # => 3
520
+ # person.pets
521
+ # # => [
522
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
523
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
524
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
525
+ # # ]
526
+ #
527
+ # person.pets.delete(Pet.find(1))
528
+ # # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
529
+ #
530
+ # person.pets.size # => 2
531
+ # person.pets
532
+ # # => [
533
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
534
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
535
+ # # ]
536
+ #
537
+ # Pet.find(1)
538
+ # # => ActiveFedora::RecordNotFound: Couldn't find Pet with id=1
539
+ #
540
+ # You can pass +Fixnum+ or +String+ values, it finds the records
541
+ # responding to the +id+ and executes delete on them.
542
+ #
543
+ # class Person < ActiveFedora::Base
544
+ # has_many :pets
545
+ # end
546
+ #
547
+ # person.pets.size # => 3
548
+ # person.pets
549
+ # # => [
550
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
551
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
552
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
553
+ # # ]
554
+ #
555
+ # person.pets.delete("1")
556
+ # # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
557
+ #
558
+ # person.pets.delete(2, 3)
559
+ # # => [
560
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
561
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
562
+ # # ]
563
+ def delete(*records)
564
+ @association.delete(*records)
565
+ end
566
+
567
+ # Destroys the +records+ supplied and removes them from the collection.
568
+ # This method will _always_ remove record from the database ignoring
569
+ # the +:dependent+ option. Returns an array with the removed records.
570
+ #
571
+ # class Person < ActiveFedora::Base
572
+ # has_many :pets
573
+ # end
574
+ #
575
+ # person.pets.size # => 3
576
+ # person.pets
577
+ # # => [
578
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
579
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
580
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
581
+ # # ]
582
+ #
583
+ # person.pets.destroy(Pet.find(1))
584
+ # # => [#<Pet id: 1, name: "Fancy-Fancy", person_id: 1>]
585
+ #
586
+ # person.pets.size # => 2
587
+ # person.pets
588
+ # # => [
589
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
590
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
591
+ # # ]
592
+ #
593
+ # person.pets.destroy(Pet.find(2), Pet.find(3))
594
+ # # => [
595
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
596
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
597
+ # # ]
598
+ #
599
+ # person.pets.size # => 0
600
+ # person.pets # => []
601
+ #
602
+ # Pet.find(1, 2, 3) # => ActiveFedora::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3)
603
+ #
604
+ # You can pass +Fixnum+ or +String+ values, it finds the records
605
+ # responding to the +id+ and then deletes them from the database.
606
+ #
607
+ # person.pets.size # => 3
608
+ # person.pets
609
+ # # => [
610
+ # # #<Pet id: 4, name: "Benny", person_id: 1>,
611
+ # # #<Pet id: 5, name: "Brain", person_id: 1>,
612
+ # # #<Pet id: 6, name: "Boss", person_id: 1>
613
+ # # ]
614
+ #
615
+ # person.pets.destroy("4")
616
+ # # => #<Pet id: 4, name: "Benny", person_id: 1>
617
+ #
618
+ # person.pets.size # => 2
619
+ # person.pets
620
+ # # => [
621
+ # # #<Pet id: 5, name: "Brain", person_id: 1>,
622
+ # # #<Pet id: 6, name: "Boss", person_id: 1>
623
+ # # ]
624
+ #
625
+ # person.pets.destroy(5, 6)
626
+ # # => [
627
+ # # #<Pet id: 5, name: "Brain", person_id: 1>,
628
+ # # #<Pet id: 6, name: "Boss", person_id: 1>
629
+ # # ]
630
+ #
631
+ # person.pets.size # => 0
632
+ # person.pets # => []
633
+ #
634
+ # Pet.find(4, 5, 6) # => ActiveFedora::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6)
635
+ def destroy(*records)
636
+ @association.destroy(*records)
637
+ end
638
+
639
+ # Specifies whether the records should be unique or not.
640
+ #
641
+ # class Person < ActiveFedora::Base
642
+ # has_many :pets
643
+ # end
644
+ #
645
+ # person.pets.select(:name)
646
+ # # => [
647
+ # # #<Pet name: "Fancy-Fancy">,
648
+ # # #<Pet name: "Fancy-Fancy">
649
+ # # ]
650
+ #
651
+ # person.pets.select(:name).uniq
652
+ # # => [#<Pet name: "Fancy-Fancy">]
653
+ def uniq
654
+ @association.uniq
655
+ end
656
+
657
+ # Count all records using Solr.
658
+ #
659
+ # class Person < ActiveFedora::Base
660
+ # has_many :pets
661
+ # end
662
+ #
663
+ # person.pets.count # => 3
664
+ # person.pets
665
+ # # => [
666
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
667
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
668
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
669
+ # # ]
670
+ def count(options = {})
671
+ @association.count(options)
672
+ end
673
+
674
+ # Returns the size of the collection. If the collection hasn't been loaded,
675
+ # it executes a solr query to find the matching records. Else it calls
676
+ # <tt>collection.size</tt>.
677
+ #
678
+ # If the collection has been already loaded +size+ and +length+ are
679
+ # equivalent. If not and you are going to need the records anyway
680
+ # +length+ will take one less query. Otherwise +size+ is more efficient.
681
+ #
682
+ # class Person < ActiveFedora::Base
683
+ # has_many :pets
684
+ # end
685
+ #
686
+ # person.pets.size # => 3
687
+ # # queries solr for the number of matching records where "person_id_ssi" = 1
688
+ #
689
+ # person.pets # This will execute a solr query
690
+ # # => [
691
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
692
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
693
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
694
+ # # ]
695
+ #
696
+ # person.pets.size # => 3
697
+ # # Because the collection is already loaded, this will behave like
698
+ # # collection.size and no Solr count query is executed.
699
+ def size
700
+ @association.size
701
+ end
702
+
703
+ # Returns the size of the collection calling +size+ on the target.
704
+ # If the collection has been already loaded, +length+ and +size+ are
705
+ # equivalent. If not and you are going to need the records anyway this
706
+ # method will take one less query. Otherwise +size+ is more efficient.
707
+ #
708
+ # class Person < ActiveFedora::Base
709
+ # has_many :pets
710
+ # end
711
+ #
712
+ # person.pets.length # => 3
713
+ # # queries solr for the number of matching records where "person_id_ssi" = 1
714
+ #
715
+ # # Because the collection is loaded, you can
716
+ # # call the collection with no additional queries:
717
+ # person.pets
718
+ # # => [
719
+ # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>,
720
+ # # #<Pet id: 2, name: "Spook", person_id: 1>,
721
+ # # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
722
+ # # ]
723
+ def length
724
+ @association.length
725
+ end
726
+
727
+ # Returns +true+ if the collection is empty. If the collection has been
728
+ # loaded or the <tt>:counter_sql</tt> option is provided, it is equivalent
729
+ # to <tt>collection.size.zero?</tt>. If the collection has not been loaded,
730
+ # it is equivalent to <tt>collection.exists?</tt>. If the collection has
731
+ # not already been loaded and you are going to fetch the records anyway it
732
+ # is better to check <tt>collection.length.zero?</tt>.
733
+ #
734
+ # class Person < ActiveFedora::Base
735
+ # has_many :pets
736
+ # end
737
+ #
738
+ # person.pets.count # => 1
739
+ # person.pets.empty? # => false
740
+ #
741
+ # person.pets.delete_all
742
+ #
743
+ # person.pets.count # => 0
744
+ # person.pets.empty? # => true
745
+ def empty?
746
+ @association.empty?
747
+ end
748
+
749
+ # Returns +true+ if the collection is not empty.
750
+ #
751
+ # class Person < ActiveFedora::Base
752
+ # has_many :pets
753
+ # end
754
+ #
755
+ # person.pets.count # => 0
756
+ # person.pets.any? # => false
757
+ #
758
+ # person.pets << Pet.new(name: 'Snoop')
759
+ # person.pets.count # => 0
760
+ # person.pets.any? # => true
761
+ #
762
+ # You can also pass a block to define criteria. The behavior
763
+ # is the same, it returns true if the collection based on the
764
+ # criteria is not empty.
765
+ #
766
+ # person.pets
767
+ # # => [#<Pet name: "Snoop", group: "dogs">]
768
+ #
769
+ # person.pets.any? do |pet|
770
+ # pet.group == 'cats'
771
+ # end
772
+ # # => false
773
+ #
774
+ # person.pets.any? do |pet|
775
+ # pet.group == 'dogs'
776
+ # end
777
+ # # => true
778
+ def any?(&block)
779
+ @association.any?(&block)
780
+ end
781
+
782
+ # Returns true if the collection has more than one record.
783
+ # Equivalent to <tt>collection.size > 1</tt>.
784
+ #
785
+ # class Person < ActiveFedora::Base
786
+ # has_many :pets
787
+ # end
788
+ #
789
+ # person.pets.count #=> 1
790
+ # person.pets.many? #=> false
791
+ #
792
+ # person.pets << Pet.new(name: 'Snoopy')
793
+ # person.pets.count #=> 2
794
+ # person.pets.many? #=> true
795
+ #
796
+ # You can also pass a block to define criteria. The
797
+ # behavior is the same, it returns true if the collection
798
+ # based on the criteria has more than one record.
799
+ #
800
+ # person.pets
801
+ # # => [
802
+ # # #<Pet name: "Gorby", group: "cats">,
803
+ # # #<Pet name: "Puff", group: "cats">,
804
+ # # #<Pet name: "Snoop", group: "dogs">
805
+ # # ]
806
+ #
807
+ # person.pets.many? do |pet|
808
+ # pet.group == 'dogs'
809
+ # end
810
+ # # => false
811
+ #
812
+ # person.pets.many? do |pet|
813
+ # pet.group == 'cats'
814
+ # end
815
+ # # => true
816
+ def many?(&block)
817
+ @association.many?(&block)
818
+ end
819
+
820
+ # Returns +true+ if the given object is present in the collection.
821
+ #
822
+ # class Person < ActiveFedora::Base
823
+ # has_many :pets
824
+ # end
825
+ #
826
+ # person.pets # => [#<Pet id: 20, name: "Snoop">]
827
+ #
828
+ # person.pets.include?(Pet.find(20)) # => true
829
+ # person.pets.include?(Pet.find(21)) # => false
830
+ def include?(record)
831
+ @association.include?(record)
832
+ end
833
+
834
+ alias_method :new, :build
835
+
836
+ def proxy_association
837
+ @association
838
+ end
839
+
840
+ def to_ary
841
+ load_target.dup
842
+ end
843
+ alias_method :to_a, :to_ary
844
+
845
+ def <<(*records)
846
+ proxy_association.concat(records) && self
847
+ end
848
+ alias_method :push, :<<
849
+
850
+ def clear
851
+ delete_all
852
+ self
853
+ end
854
+
855
+ def reload
856
+ proxy_association.reload
857
+ self
858
+ end
859
+
860
+ end
861
+ end
862
+ end