Module: ActiveFedora::Relationships::ClassMethods

Extended by:
Deprecation
Defined in:
lib/active_fedora/relationships.rb

Instance Method Summary collapse

Instance Method Details

#bidirectional_relationship_query(pid, relationship_name, outbound_pids) ⇒ String

Returns a solr query for retrieving objects specified in a bidirectional relationship. This method is mostly used by internal method calls. It usea of solr_fq value defined within a relationship to attach a query filter on top of just the predicate being used. Because it is static it needs the pids defined within RELS-EXT for the outbound relationship as well as the pid of the object for the inbound portion of the relationship. If you are calling this method directly to get the query you should use the ActiveFedora::SemanticNode.relationship_query instead or use the helper method [relationship_name]_query, i.e. method “bi_parts_query” for relationship “bi_parts”. This method would only be called directly if you had something like an array of outbound pids already in something like a solr document for object that has these relationships.

Examples:

Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
  has_bidirectional_relationship "bi_series_parts", :has_part, :is_part_of, :solr_fq=>"level_t:series"
end
s = SampleAFObjRelationshipFilterQuery.new
obj = ActiveFedora::Base.new
s.bi_series_parts_append(obj)
s.pid
#=> "changeme:13025" 
obj.pid
#=> id:changeme:13026
s.bi_series_parts_query 
#=> "(id:changeme\\:13026 AND level_t:series) OR (is_part_of_s:info\\:fedora/changeme\\:13025 AND level_t:series)" 
SampleAFObjRelationshipFilterQuery.bidirectional_relationship_query(s.pid,"series_parents",["id:changeme:13026"])
#=> "(id:changeme\\:13026 AND level_t:series) OR (is_part_of_s:info\\:fedora/changeme\\:13025 AND level_t:series)" 

Parameters:

  • The (String)

    pid for the object that has these inbound relationships

  • The (String)

    name of the relationship defined in the model

  • An (Array)

    array of pids to include in the query

Returns:

  • (String)


408
409
410
411
412
413
414
415
416
# File 'lib/active_fedora/relationships.rb', line 408

def bidirectional_relationship_query(pid,relationship_name,outbound_pids)
  outbound_query = outbound_relationship_query("#{relationship_name}_outbound",outbound_pids) 
  inbound_query = inbound_relationship_query(pid,"#{relationship_name}_inbound")
  query = outbound_query # use outbound_query by default
  if !inbound_query.empty?
    query << " OR (" + inbound_relationship_query(pid,"#{relationship_name}_inbound") + ")"
  end
  return query      
end

#create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts = {}) ⇒ Object

Deprecated.

create_bidirectional_relationship_finders will be removed in active-fedora 6.0

Generates relationship finders for predicates that point in both directions and registers predicate relationships for each direction.

Parameters:

  • name (String)

    Name of the relationship method(s) to create

  • outbound_predicate (Symbol)

    Predicate used in outbound relationships

  • inbound_predicate (Symbol)

    Predicate used in inbound relationships

  • opts (Hash) (defaults to: {})

    (optional)



610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
# File 'lib/active_fedora/relationships.rb', line 610

def create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts={})
  inbound_method_name = name.to_s+"_inbound"
  outbound_method_name = name.to_s+"_outbound"
  Deprecation.silence(ActiveFedora::Relationships::ClassMethods) do
  has_relationship(outbound_method_name, outbound_predicate, opts)
  has_relationship(inbound_method_name, inbound_predicate, opts.merge!(:inbound=>true))

  #create methods that mirror the outbound append and remove with our bidirectional name, assume just add and remove locally        
  create_bidirectional_relationship_name_methods(name,outbound_method_name)

  end
  
  class_eval <<-END, __FILE__, __LINE__
  def #{name}(opts={})
    Deprecation.silence(ActiveFedora::Relationships) do
      load_bidirectional("#{name}", :#{inbound_method_name}, :#{outbound_method_name}, opts)
    end
  end
  def #{name}_ids
    #{name}(:response_format => :id_array)
  end
  def #{name}_from_solr
    #{name}(:response_format => :load_from_solr)
  end
  def #{name}_query
    relationship_query("#{name}")
  end
  END
end

#create_bidirectional_relationship_name_methods(name, outbound_name) ⇒ Object

Deprecated.

create_bidirectional_relationship_name_methods will be removed in active-fedora 6.0

Similar to create_relationship_name_methods except it is used when an ActiveFedora::Base model class

declares has_bidirectional_relationship.  we are merely creating an alias for outbound portion of bidirectional
@param [String] bidirectional relationship name
@param [String] outbound relationship method name associated with the bidirectional relationship ([bidirectional_name]_outbound)
@example
  has_bidirectional_relationship "members", :has_collection_member, :is_member_of_collection

  Method members_outbound_append and members_outbound_remove added
  This method will create members_append which does same thing as members_outbound_append
  and will create members_remove which does same thing as members_outbound_remove


653
654
655
656
657
658
# File 'lib/active_fedora/relationships.rb', line 653

def create_bidirectional_relationship_name_methods(name,outbound_name)
  append_method_name = "#{name.to_s.downcase}_append"
  remove_method_name = "#{name.to_s.downcase}_remove"
  self.send(:define_method,:"#{append_method_name}") {|object| add_relationship_by_name(outbound_name,object)}
  self.send(:define_method,:"#{remove_method_name}") {|object| remove_relationship_by_name(outbound_name,object)}
end

#create_inbound_relationship_finders(name, predicate, opts = {}) ⇒ Object



562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
# File 'lib/active_fedora/relationships.rb', line 562

def create_inbound_relationship_finders(name, predicate, opts = {})
  class_eval <<-END, __FILE__, __LINE__
  def #{name}(opts={})
    Deprecation.silence(ActiveFedora::Relationships) do
      load_inbound_relationship('#{name}', '#{predicate}', opts)
    end
  end
  def #{name}_ids
    #{name}(:response_format => :id_array)
  end
  def #{name}_from_solr
    #{name}(:response_format => :load_from_solr)
  end
  def #{name}_query
    relationship_query("#{name}")
  end
  END
end

#create_outbound_relationship_finders(name, predicate, opts = {}) ⇒ Object



581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/active_fedora/relationships.rb', line 581

def create_outbound_relationship_finders(name, predicate, opts = {})
  class_eval <<-END, __FILE__, __LINE__
  def #{name}(opts={})
    Deprecation.silence(ActiveFedora::Relationships) do
      load_outbound_relationship(#{name.inspect}, #{predicate.inspect}, opts)
    end
  end
  def #{name}_ids
    #{name}(:response_format => :id_array)
  end
  def #{name}_from_solr
    #{name}(:response_format => :load_from_solr)
  end
  def #{name}_query
    relationship_query("#{name}")
  end
  END
end

#create_relationship_name_methods(name) ⇒ Object

Deprecated.

create_relationship_name_methods will be removed in active-fedora 6.0

Used in has_relationship call to create dynamic helper methods to append and remove objects to and from a relationship

Examples:

For the following relationship

has_relationship "audio_records", :has_part, :type=>AudioRecord

Methods audio_records_append and audio_records_remove are created.
Boths methods take an object that is kind_of? ActiveFedora::Base as a parameter

Parameters:

  • relationship (String)

    name to create helper methods for



531
532
533
534
535
536
537
# File 'lib/active_fedora/relationships.rb', line 531

def create_relationship_name_methods(name)
  append_method_name = "#{name.to_s.downcase}_append"
  remove_method_name = "#{name.to_s.downcase}_remove"

  self.send(:define_method,:"#{append_method_name}") {|object| Deprecation.silence(ActiveFedora::Relationships) { add_relationship_by_name(name,object) } }
  self.send(:define_method,:"#{remove_method_name}") {|object| Deprecation.silence(ActiveFedora::Relationships) {remove_relationship_by_name(name,object) } }        
end

#has_bidirectional_relationship(name, outbound_predicate, inbound_predicate, opts = {}) ⇒ Object

Deprecated.

use ActiveFedora::Base.has_and_belongs_to_many. has_bidirectional_relationship will be removed in active-fedora 6.0

Generates relationship finders for predicates that point in both directions

Example:

has_bidirectional_relationship("parts", :has_part, :is_part_of)

will create three instance methods: parts_outbound, and parts_inbound and parts the inbound and outbound methods are the same that would result from calling create_inbound_relationship_finders and create_outbound_relationship_finders The third method combines the results of both and handles generating appropriate solr queries where necessary.

Parameters:

  • name (String)

    of the relationship method(s) to create

  • outbound_predicate (Symbol)

    Predicate used in outbound relationships

  • inbound_predicate (Symbol)

    Predicate used in inbound relationships

  • opts (Hash) (defaults to: {})


557
558
559
# File 'lib/active_fedora/relationships.rb', line 557

def has_bidirectional_relationship(name, outbound_predicate, inbound_predicate, opts={})
  create_bidirectional_relationship_finders(name, outbound_predicate, inbound_predicate, opts)
end

#has_relationship(name, predicate, opts = {}) ⇒ Object

Deprecated.

use ActiveFedora::Base.has_many or ActiveFedora::Base.belongs_to. has_relationship will be removed in active-fedora 6.0

Allows for a relationship to be treated like any other attribute of a model class. You define relationships in your model class using this method. You then have access to several helper methods to list, append, and remove objects from the list of relationships.

Examples to define two relationships

class AudioRecord < ActiveFedora::Base

 has_relationship "oral_history", :has_part, :inbound=>true, :type=>OralHistory
 # returns all similar audio
 has_relationship "similar_audio", :has_part, :type=>AudioRecord
 #returns only similar audio with format wav
 has_relationship "similar_audio_wav", :has_part, :solr_fq=>"format_t:wav"

The first two parameters are required:

name: relationship name
predicate: predicate for the relationship
opts:
  possible parameters  
    :inbound => if true loads an external relationship via Solr (defaults to false)
    :type => The type of model to use when instantiated an object from the pid in this relationship (defaults to ActiveFedora::Base)
    :solr_fq => Define a solr query here if you want to filter out some objects in your relationship (must be a properly formatted solr query)

If inbound is true it expects the relationship to be defined by another object’s RELS-EXT and to load that relationship from Solr. Otherwise, if inbound is true the relationship is stored in this object’s RELS-EXT datastream

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 and one is outbound as shown in the example above. A full list of possible predicates are defined by predicate_mappings

For the oral_history relationship in the example above the following helper methods are created:

oral_history: returns array of OralHistory objects that have this AudioRecord with predicate :has_part 
oral_history_ids: Return array of pids for OralHistory objects that have this AudioRecord with predicate :has_part
oral_history_query: Return solr query that can be used to retrieve related objects as solr documents

For the outbound relationship “similar_audio” there are two additional methods to append and remove objects from that relationship since it is managed internally:

similar_audio: Return array of AudioRecord objects that have been added to similar_audio relationship
similar_audio_ids:  Return array of AudioRecord object pids that have been added to similar_audio relationship
similar_audio_query: Return solr query that can be used to retrieve related objects as solr documents
similar_audio_append: Add an AudioRecord object to the similar_audio relationship
similar_audio_remove: Remove an AudioRecord from the similar_audio relationship


503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/active_fedora/relationships.rb', line 503

def has_relationship(name, predicate, opts = {})
  opts = {:singular => nil, :inbound => false}.merge(opts)
  if opts[:inbound] == true
    register_relationship_desc(:inbound, name, predicate, opts)
    register_predicate(:inbound, predicate)
    create_inbound_relationship_finders(name, predicate, opts)
  else
    #raise "Duplicate use of predicate for named outbound relationship \"#{predicate.inspect}\" not allowed" if named_predicate_exists_with_different_name?(:self,name,predicate)
    register_relationship_desc(:self, name, predicate, opts)
    register_predicate(:self, predicate)
    create_relationship_name_methods(name)
    create_outbound_relationship_finders(name, predicate, opts)
  end
end

#inbound_relationship_query(pid, relationship_name) ⇒ String

Returns a solr query for retrieving objects specified in an inbound relationship. This method is mostly used by internal method calls. It utilizes any solr_fq value defined within a relationship to attach a query filter on top of just the predicate being used. Because it is static it needs the pid of the object that has the inbound relationships passed in. If you are calling this method directly to get the query you should use the ActiveFedora::SemanticNode.relationship_query instead or use the helper method [relationship_name]_query, i.e. method “parts_query” for relationship “parts”. This method would only be called directly if you were working only with Solr and already had the pid for the object in something like a solr document.

Examples:

Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
  #returns all parts
  has_relationship "parts", :is_part_of, :inbound=>true
  #returns only parts that have level to "series"
  has_relationship "series_parts", :is_part_of, :inbound=>true, :solr_fq=>"level_t:series"
end
s = SampleAFObjRelationshipFilterQuery.new
s.pid 
#=> id:changeme:13020
s.series_parts_query
#=> "is_part_of_s:info\\:fedora/changeme\\:13021 AND level_t:series"
SampleAFObjRelationshipFilterQuery.inbound_relationship_query(s.pid,"series_parts")
#=> "is_part_of_s:info\\:fedora/changeme\\:13021 AND level_t:series"

Parameters:

  • The (String)

    pid for the object that has these inbound relationships

  • The (String)

    name of the relationship defined in the model

Returns:

  • (String)


363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/active_fedora/relationships.rb', line 363

def inbound_relationship_query(pid,relationship_name)
  query = ""
  subject = :inbound
  if relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name)
    predicate = relationships_desc[subject][relationship_name][:predicate]
    query = ActiveFedora::SolrService.construct_query_for_rel(predicate, "info:fedora/#{pid}")
    if relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name) && relationships_desc[subject][relationship_name].has_key?(:solr_fq)
      solr_fq = relationships_desc[subject][relationship_name][:solr_fq]
      query << " AND " unless query.empty?
      query << solr_fq
    end
  end
  query
end

#is_bidirectional_relationship?(relationship_name) ⇒ Boolean

Tests if the relationship name passed is in bidirectional

Parameters:

  • relationship (String)

    name to test

Returns:

  • (Boolean)


281
282
283
# File 'lib/active_fedora/relationships.rb', line 281

def is_bidirectional_relationship?(relationship_name)
  (relationships_desc.has_key?(:self)&&relationships_desc.has_key?(:inbound)&&relationships_desc[:self].has_key?("#{relationship_name}_outbound") && relationships_desc[:inbound].has_key?("#{relationship_name}_inbound")) 
end

#outbound_relationship_query(relationship_name, outbound_pids) ⇒ String

Returns a solr query for retrieving objects specified in an outbound relationship. This method is mostly used by internal method calls. It utilizes any solr_fq value defined within a relationship to attach a query filter when querying solr on top of just the predicate being used. Because it is static it needs the pids defined within RELS-EXT for this relationship to be passed in. If you are calling this method directly to get the query you should use the ActiveFedora::SemanticNode.relationship_query instead or use the helper method [relationship_name]_query, i.e. method “parts_query” for relationship “parts”. This method would only be called directly if you had something like an array of outbound pids already in something like a solr document for object that has these relationships.

Examples:

Class SampleAFObjRelationshipFilterQuery < ActiveFedora::Base
  #points to all parents linked via is_member_of
  has_relationship "parents", :is_member_of
  #returns only parents that have a level value set to "series"
  has_relationship "series_parents", :is_member_of, :solr_fq=>"level_t:series"
end
s = SampleAFObjRelationshipFilterQuery.new
obj = ActiveFedora::Base.new
s.series_parents_append(obj)
s.series_parents_query 
#=> "(id:changeme\\:13020 AND level_t:series)" 
SampleAFObjRelationshipFilterQuery.outbound_relationship_query("series_parents",["id:changeme:13020"])
#=> "(id:changeme\\:13020 AND level_t:series)" 

Parameters:

  • The (String)

    name of the relationship defined in the model

  • An (Array)

    array of pids to include in the query

Returns:

  • (String)


314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/active_fedora/relationships.rb', line 314

def outbound_relationship_query(relationship_name,outbound_pids)
  query = ActiveFedora::SolrService.construct_query_for_pids(outbound_pids)
  subject = :self
  if relationships_desc.has_key?(subject) && relationships_desc[subject].has_key?(relationship_name) && relationships_desc[subject][relationship_name].has_key?(:solr_fq)
    solr_fq = relationships_desc[subject][relationship_name][:solr_fq]
    unless query.empty?
      #substitute in the filter query for each pid so that it is applied to each in the query
      query_parts = query.split(/OR/)
      query = ""
      query_parts.each_with_index do |query_part,index|
        query_part.strip!
        query << " OR " if index > 0
        query << "(#{query_part} AND #{solr_fq})"
      end
    else
      query = solr_fq
    end
  end
  query
end

#register_predicate(subject, predicate) ⇒ Object



454
455
456
457
458
459
# File 'lib/active_fedora/relationships.rb', line 454

def register_predicate(subject, predicate)
  register_subject(subject)
  if !relationships[subject].has_key?(predicate) 
    relationships[subject][predicate] = []
  end
end

#register_relationship_desc(subject, name, predicate, opts = {}) ⇒ Object

Internal method that adds relationship name and predicate pair to either an outbound (:self) or inbound (:inbound) relationship types. Refer to ActiveFedora::SemanticNode.has_relationship for information on what metadata will be persisted.

Parameters:

  • Subject (Symbol)

    name to register

  • Name (String)

    of relationship being registered

  • Fedora (Symbol)

    ontology predicate to use

  • Any (Hash)

    options passed to has_relationship such as :type, :solr_fq, etc.



434
435
436
437
438
# File 'lib/active_fedora/relationships.rb', line 434

def register_relationship_desc(subject, name, predicate, opts={})
  register_relationship_desc_subject(subject)
  opts.merge!({:predicate=>predicate})
  relationships_desc[subject][name] = opts
end

#register_relationship_desc_subject(subject) ⇒ Object

Internal method that ensures a relationship subject such as :self and :inbound exist within the relationships_desc hash tracking relationships metadata.

Parameters:

  • Subject (Symbol)

    name to register (will probably be something like :self or :inbound)



422
423
424
425
426
# File 'lib/active_fedora/relationships.rb', line 422

def register_relationship_desc_subject(subject)
  unless relationships_desc.has_key?(subject) 
    relationships_desc[subject] = {} 
  end
end

#register_subject(subject) ⇒ Object



448
449
450
451
452
# File 'lib/active_fedora/relationships.rb', line 448

def register_subject(subject)
  if !relationships.has_key?(subject) 
      relationships[subject] = {} 
  end
end

#relationshipsObject

relationships are tracked as a hash of structure

Examples:

ds.relationships # => {:self=>{:has_model=>["afmodel:SimpleThing"],:has_part=>["demo:20"]},:inbound=>{:is_part_of=>["demo:6"]} 


443
444
445
# File 'lib/active_fedora/relationships.rb', line 443

def relationships
  @class_relationships ||= Hash[:self => {}]
end