Class: ActiveFedora::Base
- Inherits:
-
Object
- Object
- ActiveFedora::Base
- Includes:
- SemanticNode
- Defined in:
- lib/active_fedora/base.rb
Overview
This class ties together many of the lower-level modules, and implements something akin to an ActiveRecord-alike interface to fedora. If you want to represent a fedora object in the ruby space, this is the class you want to extend.
The Basics
class Oralhistory < ActiveFedora::Base
:name => "properties", :type => ActiveFedora::SimpleDatastream do |m|
m.field "narrator", :string
m.field "narrator", :text
end
end
The above example creates a Fedora object with a metadata datastream named “properties”, which is composed of a narrator and bio field.
Datastreams defined with has_metadata
are accessed via the datastreams
member hash.
Direct Known Subclasses
Instance Attribute Summary
Attributes included from SemanticNode
#load_from_solr, #relationships_loaded, #subject
Class Method Summary collapse
-
.assign_pid(obj) ⇒ String
if you are doing sharding, override this method to do something other than use a sequence.
-
.connection_for_pid(pid) ⇒ Rubydora::Repository
Uses Base.shard_index to find or create the rubydora connection for this pid.
- .datastream_class_for_name(dsid) ⇒ Object
- .pids_from_uris(uris) ⇒ Object
-
.shard_index(pid) ⇒ Integer
This is where your sharding strategy is implemented – it’s how we figure out which shard an object will be (or was) written to.
Instance Method Summary collapse
- #==(comparison_object) ⇒ Object
-
#adapt_to(klass) ⇒ Object
This method adapts the inner_object to a new ActiveFedora::Base implementation This is intended to minimize redundant interactions with Fedora.
-
#adapt_to_cmodel ⇒ Object
Examines the :has_model assertions in the RELS-EXT.
- #clone ⇒ Object
-
#clone_into(new_object) ⇒ Object
Clone the datastreams from this object into the provided object, while preserving the pid of the provided object.
-
#create_date ⇒ Object
return the create_date of the inner object (unless it’s a new object).
-
#id ⇒ Object
Needed for the nested form helper.
-
#init_with(inner_obj) ⇒ Object
Initialize an empty model object and set the
inner_obj
example:. -
#initialize(attrs = nil) ⇒ Base
constructor
Constructor.
-
#inner_object ⇒ Object
:nodoc.
-
#internal_uri ⇒ Object
return the internal fedora URI.
- #label ⇒ Object
- #mark_for_destruction ⇒ Object
- #marked_for_destruction? ⇒ Boolean
- #method_missing(name, *args) ⇒ Object
-
#modified_date ⇒ Object
return the modification date of the inner object (unless it’s a new object).
- #new? ⇒ Boolean
-
#new_object? ⇒ Boolean
Has this object been saved?.
-
#new_record? ⇒ Boolean
Required by associations.
-
#owner_id ⇒ Object
return the owner id.
- #owner_id=(owner_id) ⇒ Object
- #persisted? ⇒ Boolean
-
#pid ⇒ Object
return the pid of the Fedora Object if there is no fedora object (loaded from solr) get the instance var TODO make inner_object a proxy that can hold the pid.
- #pretty_pid ⇒ Object
-
#reify ⇒ Object
** EXPERIMENTAL ** This method returns a new object of the same class, with the internal SolrDigitalObject replaced with an actual DigitalObject.
-
#reify! ⇒ Object
** EXPERIMENTAL ** This method reinitializes a lightweight, loaded-from-solr object with an actual DigitalObject inside.
-
#reload ⇒ Object
Reloads the object from Fedora.
- #state ⇒ Object
- #to_key ⇒ Object
- #to_param ⇒ Object
Methods included from SemanticNode
#add_relationship, #assert_kind_of, #clear_relationship, #conforms_to?, #ids_for_outbound, #inbound_relationship_predicates, #inbound_relationships, #load_relationships, #object_relations, #outbound_relationship_predicates, #outbound_relationships, #relationship_predicates, #relationships, #relationships_are_dirty, #relationships_are_dirty=, #relationships_desc, #remove_relationship
Constructor Details
#initialize(attrs = nil) ⇒ Base
Constructor. You may supply a custom :pid
, or we call the Fedora Rest API for the next available Fedora pid, and mark as new object. Also, if attrs
does not contain :pid
but does contain :namespace
it will pass the :namespace
value to Fedora::Repository.nextid to generate the next pid available within the given namespace.
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/active_fedora/base.rb', line 79 def initialize(attrs = nil) attrs = {} if attrs.nil? @association_cache = {} 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 |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/active_fedora/base.rb', line 35 def method_missing(name, *args) 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 |
Class Method Details
.assign_pid(obj) ⇒ String
if you are doing sharding, override this method to do something other than use a sequence
184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/active_fedora/base.rb', line 184 def self.assign_pid(obj) args = {} args[:namespace] = obj.namespace if obj.namespace # TODO: This juggling of Fedora credentials & establishing connections should be handled by # an establish_fedora_connection method,possibly wrap it all into a fedora_connection method - MZ 06-05-2012 if ActiveFedora.config.sharded? credentials = ActiveFedora.config.credentials[0] else credentials = ActiveFedora.config.credentials end fedora_connection[0] ||= ActiveFedora::RubydoraConnection.new(credentials) fedora_connection[0].connection.mint(args) end |
.connection_for_pid(pid) ⇒ Rubydora::Repository
Uses shard_index to find or create the rubydora connection for this pid
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/active_fedora/base.rb', line 131 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 |
.datastream_class_for_name(dsid) ⇒ Object
159 160 161 |
# File 'lib/active_fedora/base.rb', line 159 def self.datastream_class_for_name(dsid) ds_specs[dsid] ? ds_specs[dsid].fetch(:type, ActiveFedora::Datastream) : ActiveFedora::Datastream end |
.pids_from_uris(uris) ⇒ Object
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/active_fedora/base.rb', line 334 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 |
.shard_index(pid) ⇒ Integer
This is where your sharding strategy is implemented – it’s how we figure out which shard an object will be (or was) written to. Given a pid, it decides which shard that pid will be written to (and thus retrieved from). For a given pid, as long as your shard configuration remains the same it will always return the same value. If you’re not using sharding, this will always return 0, meaning use the first/only Fedora Repository in your configuration. Default strategy runs a modulo of the md5 of the pid against the number of shards. If you want to use a different sharding strategy, override this method. Make sure that it will always return the same value for a given pid and shard configuration.
150 151 152 153 154 155 156 |
# File 'lib/active_fedora/base.rb', line 150 def self.shard_index(pid) if ActiveFedora.config.sharded? Digest::MD5.hexdigest(pid).hex % ActiveFedora.config.credentials.length else 0 end end |
Instance Method Details
#==(comparison_object) ⇒ Object
260 261 262 263 264 265 |
# File 'lib/active_fedora/base.rb', line 260 def ==(comparison_object) comparison_object.equal?(self) || (comparison_object.instance_of?(self.class) && comparison_object.pid == pid && !comparison_object.new_record?) end |
#adapt_to(klass) ⇒ Object
This method adapts the inner_object to a new ActiveFedora::Base implementation This is intended to minimize redundant interactions with Fedora
278 279 280 281 282 283 |
# File 'lib/active_fedora/base.rb', line 278 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 |
#adapt_to_cmodel ⇒ Object
Examines the :has_model assertions in the RELS-EXT.
If the object is of type ActiveFedora::Base, then use the first :has_model in the RELS-EXT for this object. Due to how the RDF writer works, this is currently just the first alphabetical model.
If the object was instantiated with any other class, then use that class as the base of the type the user wants rather than casting to the first :has_model found on the object.
In either case, if an extended model of that initial base model of the two cases above exists in the :has_model, then instantiate as that extended model type instead.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/active_fedora/base.rb', line 298 def adapt_to_cmodel best_model_match = self.class unless self.instance_of? ActiveFedora::Base ActiveFedora::ContentModel.known_models_for( self ).each do |model_value| # If this is of type ActiveFedora::Base, then set to the first found :has_model. best_model_match ||= model_value # If there is an inheritance structure, use the most specific case. if best_model_match > model_value best_model_match = model_value end end self.instance_of?(best_model_match) ? self : self.adapt_to(best_model_match) end |
#clone ⇒ Object
163 164 165 166 |
# File 'lib/active_fedora/base.rb', line 163 def clone new_object = self.class.create clone_into(new_object) end |
#clone_into(new_object) ⇒ Object
Clone the datastreams from this object into the provided object, while preserving the pid of the provided object
170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/active_fedora/base.rb', line 170 def clone_into(new_object) rels = Nokogiri::XML( rels_ext.content) rels.xpath("//rdf:Description/@rdf:about").first.value = new_object.internal_uri new_object.rels_ext.content = rels.to_xml datastreams.each do |k, v| next if k == 'RELS-EXT' new_object.datastreams[k].content = v.content end new_object if new_object.save end |
#create_date ⇒ Object
return the create_date of the inner object (unless it’s a new object)
245 246 247 248 249 250 251 252 253 |
# File 'lib/active_fedora/base.rb', line 245 def create_date if @inner_object.new? Time.now elsif @inner_object.respond_to? :createdDate Array(@inner_object.createdDate).first else @inner_object.profile['objCreateDate'] end end |
#id ⇒ Object
Needed for the nested form helper
210 211 212 |
# File 'lib/active_fedora/base.rb', line 210 def id ### Needed for the nested form helper self.pid end |
#init_with(inner_obj) ⇒ Object
Initialize an empty model object and set the inner_obj
example:
class Post < ActiveFedora::Base
:name => "properties", :type => ActiveFedora::SimpleDatastream
end
post = Post.allocate
post.init_with(DigitalObject.find(pid))
post.properties.title # => 'hello world'
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/active_fedora/base.rb', line 109 def init_with(inner_obj) @association_cache = {} @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] != nil && !@inner_object.datastreams[key].content_changed? && @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 |
#inner_object ⇒ Object
:nodoc
198 199 200 |
# File 'lib/active_fedora/base.rb', line 198 def inner_object # :nodoc @inner_object end |
#internal_uri ⇒ Object
return the internal fedora URI
223 224 225 |
# File 'lib/active_fedora/base.rb', line 223 def internal_uri "info:fedora/#{pid}" end |
#label ⇒ Object
236 237 238 |
# File 'lib/active_fedora/base.rb', line 236 def label Array(@inner_object.label).first end |
#mark_for_destruction ⇒ Object
66 67 68 |
# File 'lib/active_fedora/base.rb', line 66 def mark_for_destruction @marked_for_destruction = true end |
#marked_for_destruction? ⇒ Boolean
70 71 72 |
# File 'lib/active_fedora/base.rb', line 70 def marked_for_destruction? @marked_for_destruction end |
#modified_date ⇒ Object
return the modification date of the inner object (unless it’s a new object)
256 257 258 |
# File 'lib/active_fedora/base.rb', line 256 def modified_date @inner_object.new? ? Time.now : Array(@inner_object.lastModifiedDate).first end |
#new? ⇒ Boolean
48 49 50 |
# File 'lib/active_fedora/base.rb', line 48 def new? new_object? end |
#new_object? ⇒ Boolean
Has this object been saved?
53 54 55 |
# File 'lib/active_fedora/base.rb', line 53 def new_object? inner_object.new? end |
#new_record? ⇒ Boolean
Required by associations
58 59 60 |
# File 'lib/active_fedora/base.rb', line 58 def new_record? self.new_object? end |
#owner_id ⇒ Object
return the owner id
228 229 230 |
# File 'lib/active_fedora/base.rb', line 228 def owner_id Array(@inner_object.ownerId).first end |
#owner_id=(owner_id) ⇒ Object
232 233 234 |
# File 'lib/active_fedora/base.rb', line 232 def owner_id=(owner_id) @inner_object.ownerId=(owner_id) end |
#persisted? ⇒ Boolean
62 63 64 |
# File 'lib/active_fedora/base.rb', line 62 def persisted? !new_object? end |
#pid ⇒ Object
return the pid of the Fedora Object if there is no fedora object (loaded from solr) get the instance var TODO make inner_object a proxy that can hold the pid
205 206 207 |
# File 'lib/active_fedora/base.rb', line 205 def pid @inner_object.pid end |
#pretty_pid ⇒ Object
268 269 270 271 272 273 274 |
# File 'lib/active_fedora/base.rb', line 268 def pretty_pid if self.pid == UnsavedDigitalObject::PLACEHOLDER nil else self.pid end end |
#reify ⇒ Object
** EXPERIMENTAL ** This method returns a new object of the same class, with the internal SolrDigitalObject replaced with an actual DigitalObject.
317 318 319 320 321 322 |
# File 'lib/active_fedora/base.rb', line 317 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 |
#reify! ⇒ Object
** EXPERIMENTAL ** This method reinitializes a lightweight, loaded-from-solr object with an actual DigitalObject inside.
327 328 329 330 331 332 |
# File 'lib/active_fedora/base.rb', line 327 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 |
#reload ⇒ Object
Reloads the object from Fedora.
93 94 95 96 97 |
# File 'lib/active_fedora/base.rb', line 93 def reload raise ActiveFedora::ObjectNotFoundError, "Can't reload an object that hasn't been saved" unless persisted? clear_association_cache init_with(self.class.find(self.pid, cast: false).inner_object) end |
#state ⇒ Object
240 241 242 |
# File 'lib/active_fedora/base.rb', line 240 def state Array(@inner_object.state).first end |
#to_key ⇒ Object
218 219 220 |
# File 'lib/active_fedora/base.rb', line 218 def to_key persisted? ? [pid] : nil end |
#to_param ⇒ Object
214 215 216 |
# File 'lib/active_fedora/base.rb', line 214 def to_param persisted? ? to_key.join('-') : nil end |