ActiveFedora Console Tour¶
Setup¶
- You must have Fedora running in order for this to work.
You have two options for setting up the environment. 1) check out the full ActiveFedora source code, or 2) set up a rails app and run the console within that.
Option 1: Use the Source Code (recommended)¶
- see Getting the Code
- before attempting to go through this tour, make sure all of the tests pass. See Testing ActiveFedora with RSpec
Option 2: Use a Rails App¶
If you don't want to bother with checking out the source code, you should set up a rails app and run script/console within that. If you choose to take that approach, you can define the model in /app/models rather than pasting it into the console.
The Tour¶
Open the Cosnole
This will load the ruby interactive console along with the ActiveFedora classes. If you are running within the ActiveFedora sources, it will also initialize connections to Fedora & Solr at localhost:8080
cd into the root directory of your code (either the ActiveFedora source code or your Rails app), then enter the following command
script/console
Define a Model
If you are running this in a rails app, you can put this code into app/models/oral_history.rb and then restart the console. Otherwise, paste all of this directly into the console:
class OralHistory < ActiveFedora::Base
has_relationship "parts", :is_part_of, :inbound => true
has_metadata :name => "dublin_core", :type => ActiveFedora::QualifiedDublinCoreDatastream do |m|
# With QualifiedDublinCoreDatastreams, you only have to declare variations from the standard set of DCMI Terms. The rest are automatically included.
m.field "subject_heading", :string, :xml_node => "subject", :encoding => "LCSH"
end
has_metadata :name => "properties", :type => ActiveFedora::MetadataDatastream do |m|
# For metadata that doesn't fit elsewhere, you can create simple xml documents.
m.field "my_metadata_field", :string
end
end
Initialize the connections to Fedora and Solr
ActiveFedora::SolrService.register(SOLR_URL) Fedora::Repository.register(FEDORA_URL)
Create an instance of the OralHistory class
oh = OralHistory.newGet the pid of your new object
oh.pid => "changeme:30"
This pid was retrieved from Fedora's getNextPid method. Your object will not show up in Fedora until you save it using oh.save.
RELATIONSHIPS¶
ActiveFedora provides convenience methods for creating and editing RELS-EXT relationships. It also auto-generates methods for using Solr to search based on these relationships.
List the object's relationships.
oh.relationships
=> {:self=>{}}
Call the "parts" method that was created by the has_relationship line in your class definition.oh.parts => []Now create another Fedora object and make it assert that it's a part of the OralHistory object, then save it to Fedora.
part = ActiveFedora::Base.new
part.add_relationship(:is_part_of, oh)
=> true
part.relationships
=> {:self=>{:is_part_of=>["info:fedora/changeme:233"]}}
part.save
=> ...
You can now see that object in Fedora by going to http://localhost:8080/fedora/objects/{PID} and you can see the relationship asserted in http://localhost:8080/fedora/objects/{PID}/datastreams/RELS-EXT/content
Now look and see that the object you created shows up when you call oh.parts
oh.parts
=> ...
oh.parts.each {|pt| puts pt.pid }
=> ...
oh.parts(:response_format=>:id_array)
=> ...
Note that you didn't have to save the oral history in order for this relationship to show up in solr because it is an inbound relationship. The child asserts :is_member_of rather than the parent asserting :has_member, so you only have to save the child to solr in order for it to work.
Collection Members
As of 1.0.4, all instances of ActiveFedoraL::Base and its subclasses have convenience methods for tracking collection members. We mainly use this to add references to file asset objects.
These methods are also an example of what you would get if you declared the following in one of your models.
has_relationship "collection_members", :has_collection_member, :inbound=>false
Create a new object and add it to the OralHistory's collection members. This time you have to save the object in order for the relationship to show up in solr because it is an outbound relationship where the OralHistory asserts :has_collection_member and points to the collection member object.cm = ActiveFedora::Base.new cm.pid => changeme:9 oh.collection_members_append(cm) oh.save oh.collection_members(:response_format => :id_array) => ["changeme:9"]
DATASTREAMS & METADATA¶
Blobs (a.k.a. File Datastreams, a.k.a Managed Content Datastreams)
file = File.new('spec/fixtures/minivan.jpg')
=> #<File:spec/fixtures/minivan.jpg>
file_ds = ActiveFedora::Datastream.new(:dsID => "minivan", :dsLabel => 'hello', :controlGroup => 'M', :blob => file)
=> ...
oh.add_datastream(file_ds)
=> "minivan"
oh.save
=> true
Now user your browser to find the file datastreams in Fedora ...
MetadataDatastreams
prop = oh.datastreams["properties"]
prop.fields
=> {:my_metadata_field=>{:type=>:string, :values=>[]}}
prop.my_metadata_field_values << "my value"
=> ["my value"]
prop.fields
=> {:my_metadata_field=>{:type=>:string, :values=>["my value"]}}
QualifiedDublinCoreDatastreams
QualifiedDublinCoreDatastream is a subclass of MetadataDatastream that is pre-configured to support all of the DCMI Metadata Terms.
oh.datastreams.keys => ["RELS-EXT", "DC", "dublin_core", "properties"] dc = oh.datastreams["dublin_core"] dc.class => ActiveFedora::QualifiedDublinCoreDatastream dc.fields => ... dc.subject_values => [] dc.subject_heading_values => [] dc.subject_values << "foo" => ["foo"] dc.subject_heading_values = ["bar", "baz"] => ["bar", "baz"] dc.subject_values => ["foo"] dc.subject_heading_values => ["bar", "baz"]
Serializing Metadata
dc.to_dc_xml => "<dc xmlns:dcterms='http://purl.org/dc/terms/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><dcterms:subject xsi:type='LCSH'>bar</dcterms:subject><dcterms:subject xsi:type='LCSH'>baz</dcterms:subject><dcterms:subject>foo</dcterms:subject></dc>" dc.to_xml => "<fields><subject_heading>bar</subject_heading><subject_heading>baz</subject_heading><subject>foo</subject></fields>" dc.to_solr => #<Solr::Document:0x1e5c0f8 @fields=[#<Solr::Field:0x1e590d8 @boost=nil, @value="bar", @name="subject_heading_field">, #<Solr::Field:0x1e5904c @boost=nil, @value="baz", @name="subject_heading_field">, #<Solr::Field:0x1e588e0 @boost=nil, @value="foo", @name="subject_field">]>
prop.to_xml => "<fields><my_metadata_field>my value</my_metadata_field></fields>" prop.to_solr => #<Solr::Document:0x1ac5638 @fields=[#<Solr::Field:0x1ac54bc @boost=nil, @value="my value", @name="my_metadata_field_field">]>
On auto-generating datatsream ids
If you don't specify a dsid, ActiveFedora will generate one for you.
file_ds2 = ActiveFedora::Datastream.new(:dsLabel => 'Minivan Plays', :altIDs => 'default', :controlGroup => 'M', :blob => file) oh.add_datastream(file_ds2) => "DS1" oh.datastreams.keys => ["DS1", "minivan", "RELS-EXT", "DC", "dublin_core", "properties"] >> oh.datastreams_in_memory["DS1"] == file_ds2 => true
You can choose a different prefix for the dsid by passing a :prefix value to add_datastream (be careful to ensure that the resulting dsid is a valid XMLString, or fedora will reject it!)
file_ds3 = ActiveFedora::Datastream.new(:dsLabel => 'Minivan Plays', :altIDs => 'default', :controlGroup => 'M', :blob => file) oh.add_datastream(file_ds3, :prefix=>"Foo") => "Foo1" oh.datastreams.keys oh.save
Retrieving Existing Objects¶
You can use the load_instance class method on any kind of ActiveFedora::Base class to load objects from Fedora.
oh.pid
=> "changeme:30"
copy_as_base = ActiveFedora::Base.load_instance("changeme:30")
copy_as_base.pid
=> "changeme:30"
copy_as_base.relationships
=> {:self=>{:conforms_to=>["info:fedora/afmodel:OralHistory"], :has_collection_member=>["info:fedora/changeme:16"]}}
copy_as_base.datastreams.keys
=> ["DS1", "Foo1", "minivan", "RELS-EXT", "DC", "dublin_core", "properties"]
As you can see, ActiveFedora::Base will load the object, its datastreams, it's generic Fedora Object information, and even its RELS-EXT relationships. It will not, however, know how to deserialize any model-specific metadata datastreams. In other words, ActiveFedora::Base treats all datastreams as generic Fedora datastreams.
>> copy_as_base.datastreams["dublin_core"].class => ActiveFedora::Datastream
If you want the model-specific metadata to be deserialized, you must call load_instance on the appropriate model class. This will load all of the same info as ActiveFedora::Base, but it will also attempt to deserialize the xml from any metadata datastreams that were declared by the has_metadata method in the model.
copy_as_oh = OralHistory.load_instance(oh.pid) copy_as_oh.datastreams["dublin_core"].class => ActiveFedora::QualifiedDublinCoreDatastream copy_as_oh.datastreams["properties"].class => ActiveFedora::MetadataDatastream copy_as_oh.datastreams["dublin_core"].subject_heading_values => ["bar", "baz"] copy_as_oh.datastreams["dublin_core"].subject_values => ["foo"]
Finding Objects¶
All descendants of ActiveFedora::Base provide a find method that will search for objects of the given class. The method is somewhat incomplete at the moment, but is functional. We are actively working on making it better.
Finding Instances of the Class¶
Imitating ActiveRecord, you can search for instances of the given class by calling find(:all) on that class. In current versions of the gem, this method searches solr using the active_fedora_model_field. In future versions it will not hit solr at all, instead relying on Fedora's Resource Index and searching for anything that asserts "conformsTo" or "hasModel" relationships pointing at the given model.Base.find(:all) OralHistory.find(:all)
Note that the results from these two searches do not overlap. OralHistory.find will only return objects that have been saved with active_fedora_model_field set to "info:fedora/afmodel:OralHistory". If you open an object as an instance of a different model and save it as that model, it will overwrite the active_fedora_model_field. This is, of course, no good. That's why the method will be rewritten in Version 1.1. In the meantime, you could search directly against Solr with queries like this:
solr_result = ActiveFedora::SolrService.instance.conn.query('conforms_to_field:info\:fedora/afmodel\:OralHistory')
This query will return a Solr::Result containing all of the objects that have conformsTo relationships pointing at info:fedora/afmodel:OralHistory in their RELS-EXT. This relationship gets added to the RELS-EXT whenever you save an object as a given ActiveFedora model and it does not get erased if you later save it as a different model.
Finding (Loading) a specific Object¶
You can use this instead of .load_instance
Base.find("changeme:30")
OralHistory.find("changeme:30")
Find By Solr¶
The find_by_solr method always searches against solr. You can use it just like .find, but it will return a Solr::Result instead of ActiveFedora objects. This is basically there in case you want to explicitly hit solr when using future versions of ActiveFedora (where the ordinary find method no longer hits solr).
Base.find_by_solr(:all) OralHistory.find_by_solr(:all)