This is actually a best practices / usage question on hwo to use Roar & representable in Rails, as I didn't find any examples of that. Here are two scenarios. I use decorator pattern.
Scenario 1:
Let's say I have a Product class that has multiple attributes & association. By default when somebody makes a request to api.com/products/1 - I want to show everything I've got, but if somebody makes a request to another action like so api.com/products/1/inventory_details - I only want to show limited view that pertains to inventory ( to make it faster for inventory lookups) or if somebody makes a request to api.com/products/1/assembly_details - I want to return a matrix of related sub assemblies along with some relevant product details.
Questions for Scenario 1 :
- Do I create a specific representer for each case like ProductRepresenter, ProductInventoryDetailRepresenter, ProductAssemblyDetailRepresenter or do I use some kind of flow control in the ProductRepresenter?
- If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
- Can I override this on action level?
Scenario 2:
Let's say I have api.com/products/1 that both my internal application can call but that I also want to expose to my clients. However I don't want my clients to see some of the attributes, like inventory details or maybe just one or two attributes. Also depending on the level access of employee, I want to limit their view / representation.
Questions for Scenario 2 :
- Do I create a specific representer for each case like ProductRepresenter, ProductClientViewRepresenter or do I use some kind of flow control in the ProductRepresenter?
- If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
- Can I override this on an action level - based on the access type like: admin vs inventory_user vs shipping_user?
Any advice would be appriciated. (I'll cross-post this on github in Roar-Rails gem)
Scenario 1 :
Yes, please do use separate classes. Don't start with
if:
and else and that kind of crap as it's done in vanilla Rails. One representer class per context is what I think is right. However, you should use modules and include those into the decorators to share common properties.You can use ::represents for that, see roar-rails.
Again, check docs for
respond_with
andrender
in roar-rails, they allow setting representers explicitely.Questions for Scenario 2 :
If it's only about hiding certain properties, you can actually try with
:if
and inject the context into the rendering/parsing call.object.to_json(context: "admin")
property :title, if: ->(options) { options[:context] == "admin" }
However, I strongly discourage
:if
in general as is always ends up in a mess of deciders. Hit me up on github, maybe we can find a way to solve this problem on a general level, with contexts or the like?