-
Notifications
You must be signed in to change notification settings - Fork 63
Patching ActiveFedora 7.x & 8.x Casting Behavior
ActiveFedora 7.x/8.x permits loading any repository object into any model, regardless of the model assertions persisted for that object (via hasModel in RELS-EXT). One way to patch this behavior and force casting to a known model for the object is presented.
For example, if you have an object asserting the Collection
model with PID test:1
, you can retrieve that object via the .find
method on another model class:
> Item.find("test:1")
# => returns an Item instance, not a Collection instance.
https://groups.google.com/d/msg/hydra-tech/t4K3rdFIfhg/p0SNT15DnvwJ
The main part of the patch is to override ActiveFedora::ContentModel.best_model_for(obj)
. In ActiveFedora 7.x/8.x, when the object's class is not a known model for the object (as asserted in the repository) and it's not ActiveFedora::Base
, then it simply returns the object's class -- i.e., the "best model" is not a "known model" in this case, which is why the .find
example above works as it does. So, here we patch best_model_for
to return only a matching class or subclass for the class of the object:
ActiveFedora::ContentModel.module_eval do
# Returns the first known model for the object is equal to or a
# subclass of the object's class.
# This bubbles up, e.g., to prevent mis-casting via `.find`.
def self.best_model_for(obj)
known_models_for(obj).find { |model| model <= obj.class }
end
end
Note that we have eliminated logic that might be needed in cases that use model class hierarchies. We are assuming that we do not need to find the most specific class model known, and that the first is sufficient.
Also note that, since ActiveFedora::ContentModel.best_model_for
may now return nil
(unlike AF 7.x/8.x), this will cause a TypeError
exception, e.g., in ActiveFedora::Core#adapt_to_cmodel
. I have decided to catch that exception and raise a custom error:
def adapt_to_cmodel
super
rescue ::TypeError
raise ContentModelError, "Cannot adapt to nil content model."
end
A more subtle change is required in ActiveFedora::FinderMethods#load_from_fedora
in order to force casting by default, e.g., when using .find
. Instead of the AF 7.x/8.x behavior, which only forces casting if the cast
parameter is nil
and klass
is ActiveFedora::Base
, here we force casting unless the cast
parameter is explicitly false
:
ActiveFedora::FinderMethods.module_eval do
# Override tries to cast by default
def load_from_fedora(pid, cast)
inner = ActiveFedora::DigitalObject.find(klass, pid)
obj = klass.allocate.init_with_object(inner)
if cast != false
obj = obj.adapt_to_cmodel
end
obj
end
end