projecthydra/active_fedora — pull request #169 by scande3 (2013-07-30 22:03:48+00:00)
Title: Support for AF content models to extend others.

(Additional note not in the commit message below: up until now we had been using a custom forked version of active_model. This is my attempt to generalize what we had been doing rather than continue to be on a separate fork. If these are deemed infeasible and no better suggestion for this type of support exists, can continue with a forked version for my institute).

In Active Fedora, it assumes quite often that a given object will have
only a single valid content model. With models in the community
starting to extend from other models (ie. Sufia or internal models at
BPL), this update makes such cases more sane. It is not the ideal
coding solution with a few illogical inconsistencies left - but it
is one that should work without breaking any legacy code.

For the below bulleted examples, I will assume the following two
models:

class GenericFile << ActiveFedora::Base

class ExtendedGenericFile << GenericFile

* Rels-Ext relationships no longer automatically alphabetically reorder
upon saving. Previously, saving an object with:

add_relationship(:has_model, "GenericFile")
add_relationship(:has_model, "ExtendedGenericFile")

would cause "ExtendedGenericFile" to appear first in the rels_ext
list. This is an issue as the first CModel is what most of the rails
code uses when loading objects. Most people would expect for the
models to be saved in the order they added them and this has been
fixed.

* Extended hierachy is added to the content models automatically. So
if you do:

ExtendedGenericFile.create

It will add the content models to the rails_ext for itself and also
for "GenericFile". This will allow code that supports only
"GenericFile" to still function and work with those functions
that level of model supports. In short, it allows relationships
that rely on "GenericFile" to still find "ExtendedGenericFile".

* belongs_to and has_many should no longer automatically cast objects.
For example, if one has:

has_many files, class_name: "GenericFile"

A call to the "files" property will return all the objects as a type
of "GenericFile".

* A ":cast" argument was added to relationships to allow for automatic
casting. For example, using the previous example,

has_many files, class_name: "GenericFile", :cast=>true

In this case, "GenericFile" objects will still be returned as such.
But "ExtendedGenericFile" objects will be instantiated as that
class. Note that only the first cmodel order on the
"ExtendedGenericFile" object is not important as it will attempt
to use the most specific class available.

* adapt_to_cmodel no longer blindly uses the first cmodel. If an object
of a class other than ActiveFedora::Base is called with it, it will
attempt to find a more specific model based on that base model.
Otherwise, it will use the first model, and cast as that unless it
finds a more specific model registered in the system (based on that
first model).

This is easily reverted to using the first cmodel blindly. But
seems like that is more unpredictable behavior.

As mentioned, not an ideal solution as still some "black magic"
decision making in there... but I believe it is overall more
consistent in how it functions. One thing that could perhaps help
greately at some point is a "best content model" field (perhaps
using the existing active_fedora_model_ssi?).