trailblazer / roar

Parse and render REST API documents using representers.

Home Page:http://www.trailblazer.to/gems/roar

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[JSON-API] Recursive has_many :children (include tree)

felixbuenemann opened this issue · comments

It should be possible to express recursive relationships using JSONAPI has_one/has_many.

Without has_one/has_many I could just use a self-referential collection:

class TaxonRepresenter < Roar::Decorator
  include Roar::JSON::JSONAPI

  LimitDepth = ->(user_options: {}, **) {
    user_options[:depth] ? depth < user_options[:depth] : true
  }

  type :taxons
  property :id

  property :name
  # ...

  collection :children, extend: self, class: Taxon, if: LimitDepth
end
# Serialize up to depth 2
TaxonRepresenter.prepare(taxon).to_hash(user_options: { depth: 2 })

However has_one/has_many requires a block, so I can't just specify self as the decorator.

After looking at the source of Roar::JSON::JSONAPI I came up with this beautiful solution hack:

class TaxonRepresenter < Roar::Decorator
  include Roar::JSON::JSONAPI

  LimitDepth = ->(user_options: {}, **) {
    user_options[:depth] ? depth < user_options[:depth] : true
  }

  type :taxons
  property :id

  class RelationshipRepresenter < self; end

  property :name
  # ...

  nested :included do
    collection :children, decorator: TaxonRepresenter, class: Taxon, if: LimitDepth
  end

  nested :relationships do
    collection :children, decorator: RelationshipRepresenter, class: Taxon, if: LimitDepth
  end

end

Surely there should be an easier solution, given that trees are not exactly uncommon.

I'm using roar master and representable 3.0.0.

After thinking some more about it. Shouldn't it be possible to call has_one/has_many without a block and then just pass decorator, class, erc as an option?

In most casey where I habe an association I will already have a usable decorator for the collection class.