class ActiveFedora::Base
Datastreams defined with has_metadata
are accessed via the datastreams
member hash.
narrator and bio field.
The above example creates a Fedora object with a metadata datastream named “properties”, which is composed of a
end
end
m.field “narrator”, :text
m.field “narrator”, :string
has_metadata :name => “properties”, :type => ActiveFedora::MetadataDatastream do |m|
class Oralhistory < ActiveFedora::Base
=The Basics
space, this is the class you want to extend.
fedora. If you want to represent a fedora object in the ruby
implements something akin to an ActiveRecord-alike interface to
This class ties together many of the lower-level modules, and
def self.assign_pid(obj)
-
(String)
- the unique pid for a new object
def self.assign_pid(obj) args = {} args[:namespace] = obj.namespace if obj.namespace raise RuntimeError, "When using shards, you must override #{self}.assign_pid()" if ActiveFedora.config.sharded? d = REXML::Document.new(connection_for_pid('0').next_pid(args)) d.elements['//pid'].text end
def self.connection_for_pid(pid)
-
(Rubydora::Repository)
- The repository that the identifier exists in.
Parameters:
-
pid
(String
) -- the identifier of the object to get the connection for
def self.connection_for_pid(pid) idx = shard_index(pid) unless fedora_connection.has_key? idx if ActiveFedora.config.sharded? fedora_connection[idx] = RubydoraConnection.new(ActiveFedora.config.credentials[idx]) else fedora_connection[idx] = RubydoraConnection.new(ActiveFedora.config.credentials) end end fedora_connection[idx].connection end
def self.create(args = {})
def self.create(args = {}) obj = self.new(args) obj.save obj end
def self.datastream_class_for_name(dsid)
def self.datastream_class_for_name(dsid) ds_specs[dsid] ? ds_specs[dsid][:type] : ActiveFedora::Datastream end
def self.load_instance_from_solr(pid,solr_doc=nil)
It will anything stored within solr such as metadata and relationships. Non-metadata datastreams will not
one passed to populate the object.
If a value is passed in for optional parameter solr_doc it will not query solr again and just use the
to populate this object.
a pid is passed in it will query solr for a corresponding solr document and then use it
It is most useful for objects used in read-only displays in order to speed up loading time. If only
It works similarly except it populates an object from Solr instead of Fedora.
This method can be used instead of ActiveFedora::Model::ClassMethods.find.
def self.load_instance_from_solr(pid,solr_doc=nil) if solr_doc.nil? result = find_by_solr(pid) raise ActiveFedora::ObjectNotFoundError, "Object #{pid} not found in solr" if result.nil? solr_doc = result.first #double check pid and id in record match raise ActiveFedora::ObjectNotFoundError, "Object #{pid} not found in Solr" unless !result.nil? && !solr_doc.nil? && pid == solr_doc[SOLR_DOCUMENT_ID] else raise "Solr document record id and pid do not match" unless pid == solr_doc[SOLR_DOCUMENT_ID] end klass = if class_str = solr_doc['active_fedora_model_s'] class_str.first.constantize else ActiveFedora::Base end profile_json = Array(solr_doc[ActiveFedora::Base.profile_solr_name]).first unless profile_json.present? raise ActiveFedora::ObjectNotFoundError, "Object #{pid} does not contain a solrized profile" end profile_hash = ActiveSupport::JSON.decode(profile_json) obj = klass.allocate.init_with(SolrDigitalObject.new(solr_doc, profile_hash, klass)) #set by default to load any dependent relationship objects from solr as well #need to call rels_ext once so it exists when iterating over datastreams obj.rels_ext obj.datastreams.each_value do |ds| if ds.respond_to?(:profile_from_hash) and (ds_prof = profile_hash['datastreams'][ds.dsid]) ds.profile_from_hash(ds_prof) end if ds.respond_to?(:from_solr) ds.from_solr(solr_doc) if ds.kind_of?(ActiveFedora::MetadataDatastream) || ds.kind_of?(ActiveFedora::NokogiriDatastream) || ( ds.kind_of?(ActiveFedora::RelsExtDatastream)) end end obj.inner_object.freeze obj end
def self.pids_from_uris(uris)
def self.pids_from_uris(uris) if uris.class == String return uris.gsub("info:fedora/", "") elsif uris.class == Array arr = [] uris.each do |uri| arr << uri.gsub("info:fedora/", "") end return arr end end
def self.shard_index(pid)
-
(Integer)
- the index of the shard this object is stored in
def self.shard_index(pid) 0 end
def ==(comparison_object)
def ==(comparison_object) comparison_object.equal?(self) || (comparison_object.instance_of?(self.class) && comparison_object.pid == pid && !comparison_object.new_record?) end
def adapt_to(klass)
This method adapts the inner_object to a new ActiveFedora::Base implementation
def adapt_to(klass) unless klass.ancestors.include? ActiveFedora::Base raise "Cannot adapt #{self.class.name} to #{klass.name}: Not a ActiveFedora::Base subclass" end klass.allocate.init_with(inner_object) end
def adapt_to_cmodel
def adapt_to_cmodel the_model = ActiveFedora::ContentModel.known_models_for( self ).first self.class != the_model ? self.adapt_to(the_model) : self end
def attributes=(properties)
def attributes=(properties) properties.each do |k, v| respond_to?(:"#{k}=") ? send(:"#{k}=", v) : raise(UnknownAttributeError, "unknown attribute: #{k}") end end
def create_date
def create_date @inner_object.new? ? Time.now : @inner_object.profile["objCreateDate"] end
def fields
system_create_date, system_modified_date, active_fedora_model_field,
ActiveFedora::MetadataDatastream datastreams, as well as
Return a hash of all available metadata fields for all
def fields # TODO this can likely be removed once find_by_fields_by_solr is removed fields = {:id => {:values => [pid]}, :system_create_date => {:values => [self.create_date], :type=>:date}, :system_modified_date => {:values => [self.modified_date], :type=>:date}, :active_fedora_model => {:values => [self.class.inspect], :type=>:symbol}} datastreams.values.each do |ds| fields.merge!(ds.fields) if [ActiveFedora::MetadataDatastream, ActiveFedora::QualifiedDublinCoreDatastream].include?(ds.class) end return fields end
def get_values_from_datastream(dsid,field_key,default=[])
def get_values_from_datastream(dsid,field_key,default=[]) if datastreams.include?(dsid) return datastreams[dsid].get_values(field_key,default) else return nil end end
def id ### Needed for the nested form helper
def id ### Needed for the nested form helper self.pid end
def init_with(inner_obj)
post.init_with(DigitalObject.find(pid))
post = Post.allocate
end
has_metadata :name => "properties", :type => ActiveFedora::MetadataDatastream
class Post < ActiveFedora::Base
example:
Initialize an empty model object and set the +inner_obj+
def init_with(inner_obj) @inner_object = inner_obj unless @inner_object.is_a? SolrDigitalObject @inner_object.original_class = self.class ## Replace existing unchanged datastreams with the definitions found in this class if they have a different type. ## Any datastream that is deleted here will cause a reload from fedora, so avoid it whenever possible ds_specs.keys.each do |key| if !@inner_object.datastreams[key].changed.include?(:content) && @inner_object.datastreams[key].class != self.class.ds_specs[key][:type] @inner_object.datastreams.delete(key) end end end load_datastreams run_callbacks :find run_callbacks :initialize self end
def initialize(attrs = nil)
+:namespace+ value to Fedora::Repository.nextid to generate the next pid available within
Also, if +attrs+ does not contain +:pid+ but does contain +:namespace+ it will pass the
next available Fedora pid, and mark as new object.
Constructor. You may supply a custom +:pid+, or we call the Fedora Rest API for the
def initialize(attrs = nil) attrs = {} if attrs.nil? attributes = attrs.dup @inner_object = UnsavedDigitalObject.new(self.class, attributes.delete(:namespace), attributes.delete(:pid)) self.relationships_loaded = true load_datastreams [:new_object,:create_date, :modified_date].each { |k| attributes.delete(k)} self.attributes=attributes run_callbacks :initialize end
def inner_object # :nodoc
def inner_object # :nodoc @inner_object end
def inspect
def inspect "#<#{self.class}:#{self.hash} @pid=\"#{pid}\" >" end
def internal_uri
def internal_uri "info:fedora/#{pid}" end
def label
def label @inner_object.label end
def label=(new_label)
def label=(new_label) @inner_object.label = new_label end
def method_missing(name, *args)
def method_missing(name, *args) # if [:collection_members, :part_of, :parts, :part_of_append, :file_objects].include? name # ActiveSupport::Deprecation.warn("Deprecation: FileManagement will not be included by default in the next version. To use #{name} add 'include ActiveFedora::FileManagement' to your model") # self.class.send :include, FileManagement # send name, *args # else dsid = corresponding_datastream_name(name) if dsid ### Create and invoke a proxy method self.class.send :define_method, name do datastreams[dsid] end self.send(name) else super end end
def modified_date
def modified_date @inner_object.new? ? Time.now : @inner_object.profile["objLastModDate"] end
def new_object=(bool)
def new_object=(bool) ActiveSupport::Deprecation.warn("ActiveFedora::Base.new_object= has been deprecated and nolonger has any effect") end
def new_object?
def new_object? inner_object.new? end
def new_record?
def new_record? self.new_object? end
def owner_id
def owner_id @inner_object.ownerId end
def owner_id=(owner_id)
def owner_id=(owner_id) @inner_object.ownerId=(owner_id) end
def persisted?
def persisted? !new_object? end
def pid
if there is no fedora object (loaded from solr) get the instance var
return the pid of the Fedora Object
def pid @inner_object.pid end
def reify
This method returns a new object of the same class, with the internal SolrDigitalObject
** EXPERIMENTAL **
def reify if self.inner_object.is_a? DigitalObject raise "#{self.inspect} is already a full digital object" end self.class.find self.pid end
def reify!
This method reinitializes a lightweight, loaded-from-solr object with an actual
** EXPERIMENTAL **
def reify! if self.inner_object.is_a? DigitalObject raise "#{self.inspect} is already a full digital object" end self.init_with DigitalObject.find(self.class,self.pid) end
def solrize_profile(solr_doc = Hash.new) # :nodoc:
def solrize_profile(solr_doc = Hash.new) # :nodoc: profile_hash = { 'datastreams' => {} } if inner_object.respond_to? :profile inner_object.profile.each_pair do |property,value| if property =~ /Date/ value = Time.parse(value) unless value.is_a?(Time) value = value.xmlschema end profile_hash[property] = value end end self.datastreams.each_pair { |dsid,ds| profile_hash['datastreams'][dsid] = ds.solrize_profile } solr_doc[self.class.profile_solr_name] = profile_hash.to_json end
def solrize_relationships(solr_doc = Hash.new)
-
solr_doc
(Hash
) -- @deafult an empty Hash
def solrize_relationships(solr_doc = Hash.new) relationships.each_statement do |statement| predicate = RelsExtDatastream.short_predicate(statement.predicate) literal = statement.object.kind_of?(RDF::Literal) val = literal ? statement.object.value : statement.object.to_str ::Solrizer::Extractor.insert_solr_field_value(solr_doc, solr_name(predicate, :symbol), val ) end return solr_doc end
def state
def state @inner_object.state end
def to_key
def to_key persisted? ? [pid] : nil end
def to_solr(solr_doc = Hash.new, opts={})
-
opts
(Hash
) -- (optional) -
solr_doc
(Hash
) -- (optional) Hash to insert the fields into
def to_solr(solr_doc = Hash.new, opts={}) unless opts[:model_only] c_time = create_date c_time = Time.parse(c_time) unless c_time.is_a?(Time) m_time = modified_date m_time = Time.parse(m_time) unless m_time.is_a?(Time) solr_doc.merge!(SOLR_DOCUMENT_ID.to_sym => pid, ActiveFedora::SolrService.solr_name(:system_create, :date) => c_time.utc.xmlschema, ActiveFedora::SolrService.solr_name(:system_modified, :date) => m_time.utc.xmlschema, ActiveFedora::SolrService.solr_name(:active_fedora_model, :symbol) => self.class.inspect) solrize_profile(solr_doc) end datastreams.each_value do |ds| ds.ensure_xml_loaded if ds.respond_to? :ensure_xml_loaded ### Can't put this in the model because it's often implemented in Solrizer::XML::TerminologyBasedSolrizer #puts "\n\nQDC #{ds.to_solr(solr_doc).inspect}" if ds.kind_of?(ActiveFedora::QualifiedDublinCoreDatastream) solr_doc = ds.to_solr(solr_doc) if ds.kind_of?(ActiveFedora::RDFDatastream) || ds.kind_of?(ActiveFedora::NokogiriDatastream) || ds.kind_of?(ActiveFedora::MetadataDatastream) end solr_doc = solrize_relationships(solr_doc) unless opts[:model_only] solr_doc end
def to_xml(xml=Nokogiri::XML::Document.parse("<xml><fields/><content/></xml>"))
def to_xml(xml=Nokogiri::XML::Document.parse("<xml><fields/><content/></xml>")) fields_xml = xml.xpath('//fields').first builder = Nokogiri::XML::Builder.with(fields_xml) do |fields_xml| fields_xml.id_ pid fields_xml.system_create_date self.create_date fields_xml.system_modified_date self.modified_date fields_xml.active_fedora_model self.class.inspect end # {:id => pid, :system_create_date => self.create_date, :system_modified_date => self.modified_date, :active_fedora_model => self.class.inspect}.each_pair do |attribute_name, value| # el = REXML::Element.new(attribute_name.to_s) # el.text = value # fields_xml << el # end datastreams.each_value do |ds| ds.to_xml(fields_xml) if ds.class.included_modules.include?(ActiveFedora::MetadataDatastreamHelper) ds.to_rels_ext if ds.kind_of?(ActiveFedora::RelsExtDatastream) end return xml.to_s end
def update_datastream_attributes(params={}, opts={})
- Example: Update the descMetadata and properties datastreams with new values -
Parameters:
-
opts
(Hash
) -- (currently ignored.) -
params
(Hash
) -- A Hash whose keys correspond to datastream ids and whose values are appropriate Hashes to submit to update_indexed_attributes on that datastream
def update_datastream_attributes(params={}, opts={}) result = params.dup params.each_pair do |dsid, ds_params| if datastreams.include?(dsid) result[dsid] = datastreams[dsid].update_indexed_attributes(ds_params) else result.delete(dsid) end end return result end
def update_indexed_attributes(params={}, opts={})
m.update_attributes({"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}, :datastreams=>["my_ds", "my_other_ds"])
or
m.update_attributes({"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}, :datastreams=>"my_ds")
use the :datastreams argument like so:
If you want to specify which datastream(s) to update,
As in update_attributes, this overwrites _all_ available fields by default.
will be overwritten.
An index of -1 will insert a new value. any existing value at the relevant index
This will result in any datastream field of name :name having the value [a,b]
{{:name=>{"0"=>"a","1"=>"b"}}
must look like this :
A convenience method for updating indexed attributes. The passed in hash
def update_indexed_attributes(params={}, opts={}) if ds = opts[:datastreams] ds_array = [] ds = [ds] unless ds.respond_to? :each ds.each do |dsname| ds_array << datastreams[dsname] end else ds_array = metadata_streams end result = {} ds_array.each do |d| result[d.dsid] = d.update_indexed_attributes(params,opts) end return result end