Howdy -
I've come across a situation where I have (decorator) Representers with properties that need to get their values not directly from the represented object but instead from a ("private") object contained in that represented object.
In my rails app I have some models that extend a base class, but instead of using single table inheritance, I'm having the base class polymorphically belong to instances of the subclasses (I didn't want to have all the disparate data from the subclasses in one giant table).
Let me set the stage using a Zoo example (not my real application of course :-)
class Animal < ActiveRecord::Base
belongs_to :species, polymorphic: true
# has fields like :weight
end
class Monkey < ActiveRecord::Base
has_one :animal, as: :species
# has unique fields like :iq, :banana_preference, :favorite_cymbals, etc
end
class Dolphin < ActiveRecord::Base
has_one :animal, as: species
# has unique fields like :fin_height, :fish_preference, etc
end
I consider the way I implement inheritance to be a internal thing for my code, and it isn't something that I want to expose in my API. In my API, I want to have JSON schemas (and representers) for Monkeys and Dolphins.
Right now I have:
class AnimalRepresenter < Roar::Decorator
include Roar::Representer::JSON
property :weight
end
class MonkeyRepresenter < AnimalRepresenter
property :iq
property :banana_preference
...
end
class DolphinRepresenter < AnimalRepresenter
property :fin_height
property :fish_preference
...
end
In my roar/representer code, I'm actually spitting these out inside a ZooRepresenter:
class ZooRepresenter < Roar::Decorator
include Roar::Representer::JSON
collection :animals,
class: lambda { # chooses Monkey or Dolphin },
decorator: lambda { # chooses MonkeyRepresenter or DolphinRepresenter },
...
end
Of course, my representers as written don't work: the animals collection in the ZooRepresenter gets a list of Animals, and the MonkeyRepresenter and DolphinRepresenter fail because animal objects don't have "iq" and "fin_height" properties.
Per the documentation, the way to go looks to be to add custom getters and setters for the monkey and dolphin representer properties, e.g.
class MonkeyRepresenter < AnimalRepresenter
property :iq, decorator_scope: true
def iq
represented.species.iq
end
def iq=(value)
represented.species.iq=value
end
...
end
This works, it is just a lot of repeated typing. So the question is, have Nick or other Roar/Representer gurus ever considerd adding a "delegate_to_someone_else" option for the property definition? So that I could instead say:
class MonkeyRepresenter < AnimalRepresenter
property :iq, decorator_scope: true, delegate_to: :species
Or is there even a better way of doing what I want?
Still loving these tools -- thanks guys.
JP