ruby-on-railsjsonrails-roarrepresentable

Strategy to create multiple representations for the same class based on criteria using ROAR gem?


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 :

  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?
  2. If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
  3. 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 :

  1. Do I create a specific representer for each case like ProductRepresenter, ProductClientViewRepresenter or do I use some kind of flow control in the ProductRepresenter?
  2. If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?
  3. 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)


Solution

  • Scenario 1 :

    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?

    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.

    1. If I create multiple representers, for the same class, how can I use represents / respond_with pattern vs respond_to / render ?

    You can use ::represents for that, see roar-rails.

    1. Can I override this on action level?

    Again, check docs for respond_with and render in roar-rails, they allow setting representers explicitely.

    Questions for Scenario 2 :

    1. 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 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?

    1. and 3., see above.