Node Inheritance Hierarchies


(Danny) #1

Hi,
I have a blog which links to blog entries. There are different types of blog entries (video, article, image), but they all have common information such as an introduction and thumbnail.
How do I set up a class structure that supports this type of inheritance in push_type?
I want to reduce duplication


(Aaron Russell) #2

You have a few options - no right or wrong way.

1. A single Article class with a kind attribute

Something like this:

class Article < PushType::Node
  KINDS = %w( Article Image Video )
  field :kind, :select, choices: KINDS, validation: { required: true }
  field :introduction, :wysiwyg
  field :thumbnail_id, :asset
  field :media_id, :asset
end

So you just have one Article model, but in your template/view you can determine the “kind” of article and change the template accordingly.

2. Multiple nodes

To be honest, node classes tend to be quite small so I don’t think there’s any major DRY sin by just creating three different node classes. So from your Blog node:

class Blog < PushType::Node
  has_child_nodes :article, :image, :video, order: :blog
end

If the duplication really bothers you or you have quite a lot of other code that you want to be shared across the three child classes then you could always put them in a Concern and include that in each class.

3. Try actual inheritance

I’ve never tried this so I don’t even know if this would work… (but I’d be interested to find out). Define a base class with the shared code and 3 separate classes that inherit from the base. Eg:

class Blog < PushType::Node
  has_child_nodes :article, :image, :video, order: :blog
end

class BlogEntry < PushType::Node
  # ... shared code
end

class Article < BlogEntry
  # ... article code
end

class Image < BlogEntry
  # ... image code
end

class Video < BlogEntry
  # ... video code
end

(Danny) #3

The duplication is minimal at the moment but it is duplication nonetheless. I didn’t like the idea of copy pasting those fields into all blog entry type classes.

I did try that and it doesn’t work. PushType displays the, say Video, form but ignores any inherited fields such as introduction and thumbnail. It does seem like something that could be implemented in the future. The system is already super flexible.It would certainly be really neat to have full inheritance support for PushType::Node.


(Aaron Russell) #4

That makes sense actually - the fields you define in any class won’t be inherited by any descendants.

In that case, option 2 from above is your best bet, and then use a concern to share common fields:

module BlogEntry
  extend ActiveSupport::Concern
  included do
    field :description, :wysiwyg
    # ... etc
  end
end

And include in to each relevant node:

class Article < PushType::Node
  include BlogEntry
end