active-fedora 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -46,11 +46,17 @@ module ActiveFedora
46
46
  ##FIX this bug, it should delete it from a copy of params in case passed to another datastream for update since this will modify params
47
47
  ##for subsequent calls if updating more than one datastream in a single update_indexed_attributes call
48
48
  current_params = params.clone
49
- # remove any fields from params that this datastream doesn't recognize
50
- current_params.delete_if {|field_name,new_values| !self.fields.include?(field_name.to_sym) }
51
49
 
50
+ # remove any fields from params that this datastream doesn't recognize
51
+ current_params.delete_if do |field_name,new_values|
52
+ if field_name.kind_of?(Array) then field_name = field_name.first end
53
+ !self.fields.include?(field_name.to_sym)
54
+ end
55
+
52
56
  result = current_params.dup
53
57
  current_params.each do |field_name,new_values|
58
+ if field_name.kind_of?(Array) then field_name = field_name.first end
59
+
54
60
  ##FIX this bug, it should delete it from a copy of params in case passed to another datastream for update
55
61
  #if field does not exist just skip it
56
62
  next if !self.fields.include?(field_name.to_sym)
@@ -50,6 +50,16 @@ module ActiveFedora::MetadataDatastreamHelper
50
50
  return solr_doc
51
51
  end
52
52
 
53
+ # ** EXPERIMENTAL **
54
+ #
55
+ # This is utilized by ActiveFedora::Base.load_instance_from_solr to set
56
+ # metadata values in this object using the Solr document passed in.
57
+ # Any keys in the solr document that map to a metadata field key within a MetadataDatastream object
58
+ # are set to the corresponding value. Any others are ignored. Solrizer::FieldNameMapper.solr_name
59
+ # is used to map solr key to field key name.
60
+ #
61
+ # ====Warning
62
+ # Solr must be synchronized with data in Fedora.
53
63
  def from_solr(solr_doc)
54
64
  fields.each do |field_key, field_info|
55
65
  field_symbol = Solrizer::FieldNameMapper.solr_name(field_key, field_info[:type])
@@ -85,12 +95,5 @@ module ActiveFedora::MetadataDatastreamHelper
85
95
  end
86
96
  return builder.to_xml
87
97
  end
88
-
89
-
90
- # protected
91
- #
92
- # def generate_solr_symbol(field_name, field_type) # :nodoc:
93
- # solr_name(field_name, field_type)
94
- # end
95
98
 
96
99
  end
@@ -84,6 +84,11 @@ class ActiveFedora::NokogiriDatastream < ActiveFedora::Datastream
84
84
  #do nothing for now
85
85
  end
86
86
 
87
+ #overriding this method just so metadatahelper method does not get called
88
+ def from_solr(solr_doc)
89
+ #do nothing for now
90
+ end
91
+
87
92
  def solrize_accessor(accessor_name, accessor_info, opts={})
88
93
  solr_doc = opts.fetch(:solr_doc, Solr::Document.new)
89
94
  parents = opts.fetch(:parents, [])
@@ -54,6 +54,15 @@ module ActiveFedora
54
54
  return solr_doc
55
55
  end
56
56
 
57
+ # ** EXPERIMENTAL **
58
+ #
59
+ # This is utilized by ActiveFedora::Base.load_instance_from_solr to load
60
+ # the relationships hash using the Solr document passed in instead of from the RELS-EXT datastream
61
+ # in Fedora. Utilizes Solrizer::FieldNameMapper.solr_name to map solr key to
62
+ # relationship predicate.
63
+ #
64
+ # ====Warning
65
+ # Solr must be synchronized with RELS-EXT data in Fedora.
57
66
  def from_solr(solr_doc)
58
67
  #cycle through all possible predicates
59
68
  PREDICATE_MAPPINGS.keys.each do |predicate|
@@ -63,19 +63,34 @@ module ActiveFedora
63
63
  end
64
64
  end
65
65
 
66
+ # ** EXPERIMENTAL **
67
+ #
68
+ # Internal method that ensures a relationship subject such as :self and :inbound
69
+ # exist within the named_relationships_desc hash tracking named relationships metadata.
70
+ # This method just calls the class method counterpart of this method.
66
71
  def register_named_subject(subject)
67
72
  self.class.register_named_subject(subject)
68
73
  end
69
74
 
75
+ # ** EXPERIMENTAL **
76
+ #
77
+ # Internal method that adds relationship name and predicate pair to either an outbound (:self)
78
+ # or inbound (:inbound) relationship types. This method just calls the class method counterpart of this method.
70
79
  def register_named_relationship(subject, name, predicate, opts)
71
80
  self.class.register_named_relationship(subject, name, predicate, opts)
72
81
  end
73
-
82
+
83
+ # ** EXPERIMENTAL **
84
+ #
85
+ # Remove the given ActiveFedora::Relationship from this object
74
86
  def remove_relationship(relationship)
75
87
  @relationships_are_dirty = true
76
88
  unregister_triple(relationship.subject, relationship.predicate, relationship.object)
77
89
  end
78
90
 
91
+ # ** EXPERIMENTAL **
92
+ #
93
+ # Remove the subject, predicate, and object triple from the relationships hash
79
94
  def unregister_triple(subject, predicate, object)
80
95
  if relationship_exists?(subject, predicate, object)
81
96
  relationships[subject][predicate].delete_if {|curObj| curObj == object}
@@ -85,6 +100,9 @@ module ActiveFedora
85
100
  end
86
101
  end
87
102
 
103
+ # ** EXPERIMENTAL **
104
+ #
105
+ # Returns true if a relationship exists for the given subject, predicate, and object triple
88
106
  def relationship_exists?(subject, predicate, object)
89
107
  outbound_only = (subject != :inbound)
90
108
  #cache the call in case it is retrieving inbound as well, don't want to hit solr too many times
@@ -138,6 +156,9 @@ module ActiveFedora
138
156
  return rels
139
157
  end
140
158
 
159
+ # ** EXPERIMENTAL **
160
+ #
161
+ # Return array of objects for a given relationship name
141
162
  def named_relationship(name)
142
163
  rels = nil
143
164
  if inbound_relationship_names.include?(name)
@@ -149,6 +170,13 @@ module ActiveFedora
149
170
  return rels
150
171
  end
151
172
 
173
+ # ** EXPERIMENTAL **
174
+ #
175
+ # Gets the named relationships hash of subject=>name=>object_array
176
+ # It has an optional parameter of outbound_only that defaults true.
177
+ # If false it will include inbound relationships in the results.
178
+ # Also, it will only reload outbound relationships if the relationships hash has changed
179
+ # since the last time this method was called.
152
180
  def named_relationships(outbound_only=true)
153
181
  #make sure to update if relationships have been updated
154
182
  if @relationships_are_dirty == true
@@ -161,6 +189,10 @@ module ActiveFedora
161
189
  outbound_only ? @named_relationships : @named_relationships.merge(:inbound=>named_inbound_relationships)
162
190
  end
163
191
 
192
+ # ** EXPERIMENTAL **
193
+ #
194
+ # Gets named relationships from the class using the current relationships hash
195
+ # and relationship name,predicate pairs.
164
196
  def named_relationships_from_class()
165
197
  rels = {}
166
198
  named_relationship_predicates.each_pair do |subj, names|
@@ -174,6 +206,11 @@ module ActiveFedora
174
206
  return rels
175
207
  end
176
208
 
209
+ # ** EXPERIMENTAL **
210
+ #
211
+ # Return hash of named_relationships defined within other objects' RELS-EXT
212
+ # It returns a hash of relationship name to arrays of objects. It requeries
213
+ # solr each time this method is called.
177
214
  def named_inbound_relationships
178
215
  rels = {}
179
216
  if named_relationships_desc.has_key?(:inbound)&&!named_relationships_desc[:inbound].empty?()
@@ -188,18 +225,30 @@ module ActiveFedora
188
225
  return rels
189
226
  end
190
227
 
228
+ # ** EXPERIMENTAL **
229
+ #
230
+ # Return hash of outbound relationship names and predicate pairs
191
231
  def outbound_named_relationship_predicates
192
232
  named_relationship_predicates.has_key?(:self) ? named_relationship_predicates[:self] : {}
193
233
  end
194
234
 
235
+ # ** EXPERIMENTAL **
236
+ #
237
+ # Return hash of inbound relationship names and predicate pairs
195
238
  def inbound_named_relationship_predicates
196
239
  named_relationship_predicates.has_key?(:inbound) ? named_relationship_predicates[:inbound] : {}
197
240
  end
198
241
 
242
+ # ** EXPERIMENTAL **
243
+ #
244
+ # Return hash of relationship names and predicate pairs
199
245
  def named_relationship_predicates
200
246
  @named_relationship_predicates ||= named_relationship_predicates_from_class
201
247
  end
202
248
 
249
+ # ** EXPERIMENTAL **
250
+ #
251
+ # Return hash of relationship names and predicate pairs from class
203
252
  def named_relationship_predicates_from_class
204
253
  rels = {}
205
254
  named_relationships_desc.each_pair do |subj, names|
@@ -211,6 +260,9 @@ module ActiveFedora
211
260
  return rels
212
261
  end
213
262
 
263
+ # ** EXPERIMENTAL **
264
+ #
265
+ # Return array all relationship names
214
266
  def relationship_names
215
267
  names = []
216
268
  named_relationships_desc.each_key do |subject|
@@ -219,18 +271,34 @@ module ActiveFedora
219
271
  names
220
272
  end
221
273
 
274
+ # ** EXPERIMENTAL **
275
+ #
276
+ # Return array of relationship names for all named inbound relationships (coming from other objects' RELS-EXT and Solr)
222
277
  def inbound_relationship_names
223
278
  named_relationships_desc.has_key?(:inbound) ? named_relationships_desc[:inbound].keys : []
224
279
  end
225
280
 
281
+ # ** EXPERIMENTAL **
282
+ #
283
+ # Return array of relationship names for all named outbound relationships (coming from this object's RELS-EXT)
226
284
  def outbound_relationship_names
227
285
  named_relationships_desc.has_key?(:self) ? named_relationships_desc[:self].keys : []
228
286
  end
229
287
 
288
+ # ** EXPERIMENTAL **
289
+ #
290
+ # Return hash of named_relationships defined within this object's RELS-EXT
291
+ # It returns a hash of relationship name to arrays of objects
230
292
  def named_outbound_relationships
231
293
  named_relationships_desc.has_key?(:self) ? named_relationships[:self] : {}
232
294
  end
233
295
 
296
+ # ** EXPERIMENTAL **
297
+ #
298
+ # Returns true if the given relationship name is a named relationship
299
+ # ====Parameters
300
+ # name: Name of relationship
301
+ # outbound_only: If false checks inbound relationships as well (defaults to true)
234
302
  def is_named_relationship?(name, outbound_only=true)
235
303
  if outbound_only
236
304
  outbound_relationship_names.include?(name)
@@ -239,14 +307,30 @@ module ActiveFedora
239
307
  end
240
308
  end
241
309
 
310
+ # ** EXPERIMENTAL **
311
+ #
312
+ # Return hash that stores named relationship metadata defined by has_relationship calls
313
+ # ====Example
314
+ # For the following relationship
315
+ #
316
+ # has_relationship "audio_records", :has_part, :type=>AudioRecord
317
+ # Results in the following returned by named_relationships_desc
318
+ # {:self=>{"audio_records"=>{:type=>AudioRecord, :singular=>nil, :predicate=>:has_part, :inbound=>false}}}
242
319
  def named_relationships_desc
243
320
  @named_relationships_desc ||= named_relationships_desc_from_class
244
321
  end
245
322
 
323
+ # ** EXPERIMENTAL **
324
+ #
325
+ # Get class instance variable named_relationships_desc that holds has_relationship metadata
246
326
  def named_relationships_desc_from_class
247
327
  self.class.named_relationships_desc
248
328
  end
249
329
 
330
+ # ** EXPERIMENTAL **
331
+ #
332
+ # Return the value of :type for the relationship for name passed in.
333
+ # It defaults to ActiveFedora::Base.
250
334
  def named_relationship_type(name)
251
335
  if is_named_relationship?(name,true)
252
336
  subject = outbound_relationship_names.include?(name)? :self : :inbound
@@ -257,6 +341,10 @@ module ActiveFedora
257
341
  return nil
258
342
  end
259
343
 
344
+ # ** EXPERIMENTAL **
345
+ #
346
+ # Add an outbound relationship for given named relationship
347
+ # See ActiveFedora::SemanticNode::ClassMethods.has_relationship
260
348
  def add_named_relationship(name, object)
261
349
  if is_named_relationship?(name,true)
262
350
  if named_relationships_desc[:self][name].has_key?(:type)
@@ -273,6 +361,9 @@ module ActiveFedora
273
361
  end
274
362
  end
275
363
 
364
+ # ** EXPERIMENTAL **
365
+ #
366
+ # Remove an object from the named relationship
276
367
  def remove_named_relationship(name, object)
277
368
  if is_named_relationship?(name,true)
278
369
  remove_relationship(outbound_named_relationship_predicates[name],object)
@@ -281,23 +372,25 @@ module ActiveFedora
281
372
  end
282
373
  end
283
374
 
375
+ # ** EXPERIMENTAL **
376
+ #
377
+ # Throws an assertion error if kind_of_model? returns false for object and model_class
378
+ # ====Parameters
379
+ # name: Name of object (just label for output)
380
+ # object: The object to test
381
+ # model_class: The model class used to in kind_of_model? check on object
284
382
  def assert_kind_of_model(name, object, model_class)
285
383
  raise "Assertion failure: #{name}: #{object.pid} does not have model #{model_class}, it has model #{relationships[:self][:has_model]}" unless object.kind_of_model?(model_class)
286
384
  end
287
385
 
288
- ############################################################################
289
- # Checks that this class is either of type passed in or a child of that type.
290
- # It also makes sure that this object was created as the same type by
291
- # checking that hasmodel and the class match. This would not match
292
- # if someone called load_instance on a Fedora Object that was created
293
- # via a different model class than the one that was recreated from Fedora.
294
- # This is a side-effect of ActiveFedora's behavior that will try to create
295
- # the object type specified with the pid given whether it is actually that
296
- # object type or not.
297
- #
298
- # If hasmodel does not match than this will return false indicated it does not
299
- # have the correct model.
300
- ############################################################################
386
+ # ** EXPERIMENTAL **
387
+ #
388
+ # Checks that this object is matches the model class passed in.
389
+ # It requires two steps to pass to return true
390
+ # 1. It has a hasModel relationship of the same model
391
+ # 2. kind_of? returns true for the model passed in
392
+ # This method can most often be used to detect if an object from Fedora that was created
393
+ # with a different model was then used to populate this object.
301
394
  def kind_of_model?(model_class)
302
395
  if self.kind_of?(model_class)
303
396
  #check has model and class match
@@ -342,33 +435,56 @@ module ActiveFedora
342
435
  # puts "=> and whose outbound relationships are #{self.outbound_relationships.inspect}"
343
436
  self.outbound_relationships.each do |predicate, targets_array|
344
437
  targets_array.each do |target|
345
- # puts ". #{predicate} #{target}"
346
- xml.root.elements["rdf:Description"].add_element(self.class.predicate_lookup(predicate), {"xmlns" => "info:fedora/fedora-system:def/relations-external#", "rdf:resource"=>target})
438
+ xmlns=String.new
439
+ case predicate
440
+ when :has_model, "hasModel", :hasModel
441
+ xmlns="info:fedora/fedora-system:def/model#"
442
+ else
443
+ xmlns="info:fedora/fedora-system:def/relations-external#"
444
+ end
445
+ # puts ". #{predicate} #{target} #{xmlns}"
446
+ xml.root.elements["rdf:Description"].add_element(self.class.predicate_lookup(predicate), {"xmlns" => "#{xmlns}", "rdf:resource"=>target})
347
447
  end
348
448
  end
349
449
  xml.to_s
350
450
  end
351
451
 
352
452
  module ClassMethods
353
-
354
- # Anticipates usage of a relationship in classes that include this module
355
- # Creates a key in the @relationships array for the predicate provided. Assumes
356
- # :self as the subject of the relationship unless :inbound => true, in which case the
357
- # predicate is registered under @relationships[:inbound][#{predicate}]
358
- #
359
- # TODO:
360
- # Custom Methods:
361
- # A custom finder method will be appended based on the relationship name.
362
- # ie.
363
- # class Foo
364
- # relationship "container", :is_member_of
365
- # end
366
- # foo = Foo.new
367
- # foo.parts
368
- #
369
- # Special Predicate Short Hand:
370
- # These symbols map to the uris of corresponding Fedora RDF predicates
371
- # :is_member_of, :has_member, :is_part_of, :has_part
453
+
454
+ # Allows for a relationship to be treated like any other attribute of a model class. You define
455
+ # named relationships in your model class using this method. You then have access to several
456
+ # helper methods to list, append, and remove objects from the list of relationships.
457
+ # ====Examples to define two relationships
458
+ # class AudioRecord < ActiveFedora::Base
459
+ #
460
+ # has_relationship "oral_history", :has_part, :inbound=>true, :type=>OralHistory
461
+ # has_relationship "similar_audio", :has_part, :type=>AudioRecord
462
+ #
463
+ # The first two parameters are required:
464
+ # name: relationship name
465
+ # predicate: predicate for the relationship
466
+ # opts:
467
+ # possible parameters
468
+ # :inbound => if true loads an external relationship via Solr (defaults to false)
469
+ # :type => The type of model to use when instantiated an object from the pid in this relationship (defaults to ActiveFedora::Base)
470
+ #
471
+ # If inbound is true it expects the relationship to be defined by another object's RELS-EXT
472
+ # and to load that relationship from Solr. Otherwise, if inbound is true the relationship is stored in
473
+ # this object's RELS-EXT datastream
474
+ #
475
+ # Word of caution - The same predicate may not be used twice for two inbound or two outbound relationships. However, it may be used twice if one is inbound
476
+ # and one is outbound as shown in the example above. A full list of possible predicates are defined by PREDICATE_MAPPINGS
477
+ #
478
+ # For the oral_history relationship in the example above the following helper methods are created:
479
+ # oral_history: returns array of OralHistory objects that have this AudioRecord with predicate :has_part
480
+ # oral_history_ids: Return array of pids for OralHistory objects that have this AudioRecord with predicate :has_part
481
+ #
482
+ # For the outbound relationship "similar_audio" there are two additional methods to append and remove objects from that relationship
483
+ # since it is managed internally:
484
+ # similar_audio: Return array of AudioRecord objects that have been added to similar_audio relationship
485
+ # similar_audio_ids: Return array of AudioRecord object pids that have been added to similar_audio relationship
486
+ # similar_audio_append: Add an AudioRecord object to the similar_audio relationship
487
+ # similar_audio_remove: Remove an AudioRecord from the similar_audio relationship
372
488
  def has_relationship(name, predicate, opts = {})
373
489
  opts = {:singular => nil, :inbound => false}.merge(opts)
374
490
  if opts[:inbound] == true
@@ -385,7 +501,32 @@ module ActiveFedora
385
501
  end
386
502
  end
387
503
 
388
- #allow duplicate has_relationship calls with same name and predicate
504
+ # Generates relationship finders for predicates that point in both directions
505
+ #
506
+ # @name Name of the relationship method(s) to create
507
+ # @outbound_predicate Predicate used in outbound relationships
508
+ # @inbound_predicate Predicate used in inbound relationships
509
+ # @opts
510
+ #
511
+ # Example:
512
+ # has_bidirectional_relationship("parts", :has_part, :is_part_of)
513
+ #
514
+ # will create three instance methods: parts_outbound, and parts_inbound and parts
515
+ # the inbound and outbound methods are the same that would result from calling
516
+ # create_inbound_relationship_finders and create_outbound_relationship_finders
517
+ # The third method combines the results of both and handles generating appropriate
518
+ # solr queries where necessary.
519
+ def has_bidirectional_relationship(name, outbound_predicate, inbound_predicate, opts={})
520
+ create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts)
521
+ end
522
+
523
+ # ** EXPERIMENTAL **
524
+ #
525
+ # Check to make sure a subject,name, and predicate triple does not already exist
526
+ # with the same subject but different name.
527
+ # This method is used to ensure conflicting has_relationship calls are not made because
528
+ # predicates cannot be reused across relationship names. Otherwise, the mapping of relationship name
529
+ # to predicate in RELS-EXT would be broken.
389
530
  def named_predicate_exists_with_different_name?(subject,name,predicate)
390
531
  if named_relationships_desc.has_key?(subject)
391
532
  named_relationships_desc[subject].each_pair do |existing_name, args|
@@ -394,24 +535,51 @@ module ActiveFedora
394
535
  end
395
536
  return false
396
537
  end
397
-
398
- # named relationships desc are tracked as a hash of structure {name => args}}
538
+
539
+ # ** EXPERIMENTAL **
540
+ #
541
+ # Return hash that stores named relationship metadata defined by has_relationship calls
542
+ # ====Example
543
+ # For the following relationship
544
+ #
545
+ # has_relationship "audio_records", :has_part, :type=>AudioRecord
546
+ # Results in the following returned by named_relationships_desc
547
+ # {:self=>{"audio_records"=>{:type=>AudioRecord, :singular=>nil, :predicate=>:has_part, :inbound=>false}}}
399
548
  def named_relationships_desc
400
549
  @class_named_relationships_desc ||= Hash[:self => {}]
401
550
  end
402
-
551
+
552
+ # ** EXPERIMENTAL **
553
+ #
554
+ # Internal method that ensures a relationship subject such as :self and :inbound
555
+ # exist within the named_relationships_desc hash tracking named relationships metadata.
403
556
  def register_named_subject(subject)
404
557
  unless named_relationships_desc.has_key?(subject)
405
558
  named_relationships_desc[subject] = {}
406
559
  end
407
560
  end
408
561
 
562
+ # ** EXPERIMENTAL **
563
+ #
564
+ # Internal method that adds relationship name and predicate pair to either an outbound (:self)
565
+ # or inbound (:inbound) relationship types.
409
566
  def register_named_relationship(subject, name, predicate, opts)
410
567
  register_named_subject(subject)
411
568
  opts.merge!({:predicate=>predicate})
412
569
  named_relationships_desc[subject][name] = opts
413
570
  end
414
-
571
+
572
+ # ** EXPERIMENTAL **
573
+ #
574
+ # Used in has_relationship call to create dynamic helper methods to
575
+ # append and remove objects to and from a named relationship
576
+ # ====Example
577
+ # For the following relationship
578
+ #
579
+ # has_relationship "audio_records", :has_part, :type=>AudioRecord
580
+ #
581
+ # Methods audio_records_append and audio_records_remove are created.
582
+ # Boths methods take an object that is kind_of? ActiveFedora::Base as a parameter
415
583
  def create_named_relationship_methods(name)
416
584
  append_method_name = "#{name.to_s.downcase}_append"
417
585
  remove_method_name = "#{name.to_s.downcase}_remove"
@@ -480,6 +648,51 @@ module ActiveFedora
480
648
  end
481
649
  END
482
650
  end
651
+
652
+ # Generates relationship finders for predicates that point in both directions
653
+ #
654
+ # @name Name of the relationship method(s) to create
655
+ # @outbound_predicate Predicate used in outbound relationships
656
+ # @inbound_predicate Predicate used in inbound relationships
657
+ # @opts
658
+ #
659
+ def create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts={})
660
+ inbound_method_name = name.to_s+"_inbound"
661
+ outbound_method_name = name.to_s+"_outbound"
662
+ create_outbound_relationship_finders(outbound_method_name, outbound_predicate, opts)
663
+ create_inbound_relationship_finders(inbound_method_name, inbound_predicate, opts)
664
+
665
+ class_eval <<-END
666
+ def #{name}(opts={})
667
+ if opts[:response_format] == :solr || opts[:response_format] == :load_from_solr
668
+ escaped_uri = self.internal_uri.gsub(/(:)/, '\\:')
669
+ query = "#{inbound_predicate}_s:\#{escaped_uri}"
670
+
671
+ outbound_id_array = #{outbound_method_name}(:response_format=>:id_array)
672
+ query = query + " OR " + ActiveFedora::SolrService.construct_query_for_pids(outbound_id_array)
673
+
674
+ solr_result = SolrService.instance.conn.query(query)
675
+
676
+ if opts[:response_format] == :solr
677
+ return solr_result
678
+ elsif opts[:response_format] == :load_from_solr || self.load_from_solr
679
+ return ActiveFedora::SolrService.reify_solr_results(solr_result,{:load_from_solr=>true})
680
+ else
681
+ return ActiveFedora::SolrService.reify_solr_results(solr_result)
682
+ end
683
+ else
684
+ ary = #{inbound_method_name}(opts) + #{outbound_method_name}(opts)
685
+ return ary.uniq
686
+ end
687
+ end
688
+ def #{name}_ids
689
+ #{name}(:response_format => :id_array)
690
+ end
691
+ def #{name}_from_solr
692
+ #{name}(:response_format => :load_from_solr)
693
+ end
694
+ END
695
+ end
483
696
 
484
697
  # relationships are tracked as a hash of structure {subject => {predicate => [object]}}
485
698
  def relationships