Eval Criteria # 7
Can an attribute value be a reference to another object?
So far, we’ve explained discrete content modeling, which is the modeling of a self-contained object.
We’ve dealt with attributes like Title and Body with the implicit assumption these are all unique to a single object and contained wholly within it. Content Object #1 has a Title and Content Object #2 as a Title and these two things have no relationship to each other. Each content object is a container for its own content, and nothing extends past the edges of that container.
Sometimes, however, it’s helpful for a content object to have a relationship with another object. We need to create a link between the two at the attribute level.
This is the opposite of discrete content modeling – this is relational content modeling – the modeling of relationships between content objects.
Say you have an Article type which stores some information about the author – there are attributes for , , and .
You start to realize, however, you’re duplicating a lot of information. Bob has written 300 articles, and his information is embedded on all of them, and he just changed his email address.
Additionally, let’s say you’d like Bob to have his own page, where you can display some extra information about him and provide a list of his articles. However, Bob isn’t an actual content object. Remember, Bob’s representation in content only exists as a handful of attributes, duplicated on hundreds of other objects.
What you need to do is create a content object to represent Bob, then somehow link all those 300 articles to that single object in such a way that Bob’s object knows about all 300 articles, and all 300 articles know about Bob’s object.
You need to create a new type for First Name, Last Name, and Email. In doing this, you can create a content object for Bob (and for every other author), and give him his own page.. You can create attributes like
Then, you need to link Bob and his articles together. Ideally, we can do this with a referential attribute, which is an attribute value that doesn’t hold any actual data, but is just a reference to another object. The attribute on Article now links over to Bob’s object. When you’re rendering our Article, you just display Bob’s name and email from whatever is on the linked object at that moment.
This model realizes some efficiencies and benefits by the association. Every article now “knows” the object of the author who wrote it, and you can maintain this person’s information in one place. With the usage of referential attributes, our repository of content begins to become a network or a graph of connections.
Ideally, all prior functionality works the same with referential attributes.
- All validation rules are still available
- We can still create custom validation, if we need to
- If repeating attributes are offered, they also apply to referential attributes (an article might have multiple authors, for example)
The complicating factor of referential modeling is that once we have a link between two content objects, we open a Pandora’s Box of potential issues. Remember the 300 articles linked to Bob? Well, Bob just quit in spectacular fashion and management wants him off the website.
Okay, just delete him.
Wait… Since that attribute is a reference, the system will automatically delete all the references to Bob’s object when that object is deleted. That will leave 300 content objects with an emptyattribute
Is this a problem? Maybe not. It could bewas optional anyway – let’s say some articles didn’t have one, and the template is designed to work around an empty attribute without breaking.
What if they were required? What if the template needs a populatedattribute or else it breaks along with a dozen integrations to external systems, all of them expecting a populated attribute (this goes back to our discussion of “predictability”.
Maintaining rules around content references is the concept of referential integrity or dependency management. Literally, how do you maintain the integrity of your references?
In some systems, you’ll be prevented from deleting an object if there are inbound references from other objects. Other systems will prompt you to mass-replace the reference with a reference to another object. Others will just allow you to complete the deletion and nullify all the references.
Additionally, many systems will offer a proactive interface editors can access to show them links between this item and others, separate from the warnings given prior to deletion.
Beyond referential attributes, a system should also extract references from rich text. If an anchor tag inside HTML somewhere in an attribute on Object A links to a URL associated with Object B, this should be discovered and enforced in the same way as a referential attribute.
Uni-directional vs Bi-directional References
Another consideration is reference directedness, which describes the directionality of the link – are links inbound, outbound, or both?
In our prior example, an article clearly points at Bob’s Article object? If so, then the links are considered bi-directional; if not, then they’re are unidirectional.content object, but is the inverse true? When examining Bob’s object, can you follow 300 inbound links back to the corresponding
Bi-directional references are unfortunately uncommon in CMS. What makes it difficult is there’s no “receiving” attribute on theobject.
If you have Bob’s object in hand, what do you check to find the inbound links? Logic would say there should be an Articles attribute which contains 300 references, but this would involve the CMS adding a “pseudo-attribute” on a type (or multiple types, if any type can be linked to), and this isn’t functionality you’ll find often.
What you can usually do is just search from the other direction: find Article objects that include a reference to Bob’s object in their attribute. It’s not quite as elegant or intuitive, but it provides the same basic result.
Relational Content Modeling UI
When editors are working with a referential property, the editorial interface matters. A referential attribute has to provide an easy way to find another specific object, potentially from thousands of other objects.
With a limited number of objects, a simple dropdown may work. Some systems have the “two-pane” approach where you can scroll through options in the left pane, and press a button to move them to the right pane.
Other systems allow browsing or searching, or some combination of the two, depending on the underlying structure of the content in the system. In tree-based systems, you can usually browse through the tree for another object. Other systems have a search interface which allows some form of full-text searching.
These interfaces usually pop up in model dialogs positioned over the rest of the editorial interface. (How did we do this before modals were possible? Very poorly.)
Content Selection and Permissions
Object selection may or may not respect permissions. If an editor doesn’t have permission to view a certain content object, should they be able to select it as a link? Usually not, since, in most systems, permissions also apply to editors and would therefore restrict content even in the editorial interface.
And what if there’s a permissions mismatch – what if our Article object had much looser permissions than our object, so a viewer might be able to view the article but not the author? If the system is managing permissions correctly, this might cause a problem when trying to view the content.
We can account for this in the rendering template, but it might be helpful if the editor was warned in advance that the permissions of the objects don’t match.
Referential attributes should be type-limited, which hopefully filters what objects can be selected.
In our example, we clearly should only allow theattribute to link to objects. In some cases you might not have any restrictions – for example, something like could be any type. But using a referential attribute usually means you’re piecing together a network of objects, and they’ll usually always be based on type.
Less ideal would be if any object can be selected, but type validation still occurs. So, the editor could select any object, but when a save was attempted, the attribute would fail validation. This would prevent invalid content, but usability is poor because then the editor has to go through the selection process again. If an object will fail validation for type, best not to allow its selection at all.
Using referential attributes, we can implement the loose pattern of a composite object, or object assembly. This is a content structure which carries minimal content in and of itself, and is just a collection of references to other objects which are labeled and structured in such a way to impart greater meaning.
For example, we might create a type for Committee, which we define as follows:
- Department (reference to a Department)
- Chair (reference to an Employee object)
- Vice Chair (reference to an Employee object)
- Members (repeating reference to multiple Employee objects)
- Minutes (repeating reference to multiple Document objects)
- Meeting Location (reference to a Facility object)
We’ll talk about repeating attributes in a later chapter.
As you can see, our Committee object carries very little “on board” content. Rather, it’s built from multiple other content objects assembled in a structure that imparts some larger meaning. A new object emerges from the aggregation of references. Our Committee type becomes a framework on which to “hang” other objects and create something larger.
This is not an explicit feature, but just a handy pattern achieved through a combination of typed, referential attributes. (The repetition aspect is handy as well, but not technically required.)
Referential attributes are powerful and can keep your content model more manageable by preventing the duplication of attribute values. However, you open a door to referential integrity issues. Once you extend the content of an object past the edges of that object, there are unintended consequences and edge cases you need to be prepared to handle.
- Can an attribute value be a reference to another object?
- How is the target object located and entered in the attribute from the interface?
- Can target objects be limited by type?
- Can referential attributes repeat?
- How do permissions affect an editor’s ability to select a target object?
- If an editor attempts to delete a object which is the target or one more links, is the editor warned?
- From the interface, can editors view all objects that are linked to a specific content object?
- How are references discovered – is this limited to referential attributes, or is rich text searched for links?
- Are references uni-directional or bi-directional?
- From the API, is it possible to find all objects with an inbound link to a specific object?