You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Just letting you know about some features that I've implemented (in a really really ugly way :P), due to time constraints I haven't had a lot of time to look at the code and needed it done asap. I will fix the code up later when I have time and possibly pull-request.
Basically we are trying to use Representable to populate our models by passing in an extremely large and complex JSON/XML document that I cannot mention due to privacy reasons. Just think Enterprise + Legacy scale :P.
Please find some time to look at our fork (Locomote).
After you've vented about how bad my code is :P, hopefully you can think of much better ways of implementing features that cater to the same requirements if that is in your interest. :)
1. Post-processing after hook and :eval parameter
Due to the complex nature of the document we are passing in, we needed a way to build relationships up between objects post-process.
The current params like parse-strategy, required too much boilerplate for what we wanted to do, we needed something more simple and needed to use it for almost half the properties.
The after hook is a method->block that is called as a last resort for linking objects together and doing post-processing on an object.
Example:
class LibraryRepresenter
after do
users.each do |user|
user.books = books.select { |book| book.user_id == user.id }
end
end
collection :books do
property :user_id
end
collection :users do
property :id
end
end
The eval hook is done specifically in context of the property, also post-process.
Better example and reasoning is shown in the next section.
2. parent attribute
Child collections and properties can access the parent representer object during post-process. Again this is due to the "spidery" nature of the documents we receive, we need to re-arrange everything into something that actually looks organised.
We literally get documents where should-be nested objects are instead in a what-is-this-i-don't-even random location. Not only this, but we have to access these objects in order to link other randomly placed objects together.
I shit you not this is what its like (replace theme with what we are actually dealing with)
class LibraryRepresenter
collection :book_names
property :name
property :book_ref
end
# Why this wrapping appears I don't know
nested :book_data
#The actual books collection for model because most of the stuff lies here and is most reliable
collection :books, as: :book_segment do
property :book_number
property :key, eval: -> { book_number[3..-1] }
property :name, eval: -> { parent.book_names.detect { |bn| bn.book_ref == ref } }
collection :infos, eval: -> { parent.infos.select {|info| info.segment_ref == ref} }
property :pricing, eval: -> { parent.pricings.detect { |p| p.key == infos.book_pricing_ref } }
property :issue_dates, eval: -> { infos.map {|info| info.try(:issue_date) } }
# + lots of other stuff we desperately need
end
collection :pricings, as: :book_pricing do
property :base_price
property :key
end
end
# This links pricings to book, sometimes they don't always appear so we can't use this for the main collection.
collection :infos, as: :book_info do
property :book_pricing_ref
property :book_segment_ref
# Sometimes doesn't appear so we have to conditionally set this
property :issue_date
property :you_get_the_idea
end
end
Multiply this x10 and now you know why the current features require too much boilerplate for what we want to do. :P
3. Default class
We didn't want to have to declare class: OpenStruct for every... single... collection for which we have about 20 or so and possibly more in the future. Setting a default class in the Config would be nice.
Example:
collection :libaries
Is the same as
collection :libaries, class: OpenStruct
4. Magic Class instantiation
For the same reason as above, we have lots of collections. We have Representable automagically find which Representable it belongs to. Kind of like how some Ruby database gems do it.
Example:
collection :libraries
Is the same as
collection :libaries, extends: LibraryRepresenter
This behaviour however does not happen if the collection is inlined as a matter of design.
5. Type-cast on parse (symbol or class constant)
We want to be able to use symbols because of the auto-load nature of rails but also we wanted the type casting to happen immediately and not during render.
Example:
property :book_name, type: BookName
property :book_name, type: :book_name
book = OpenStruct.extend(BookRepresenter).from_json({book_name: 'A Song of Ice and Fire'}.to_json)
book.book_name.class
$ => BookName
6. Always return [] and force conversion to array for collections
Due to the inconsistent nature of the documents we are receiving we needed collections to always return [] if the fragment doesn't exist and always be parsed/set as an array, no matter what even if it is sent in as a singular (even in JSON).
Single items are wrapped in [] before being parsed if Representable knows it should be a collection.
7. :set parameter
During parsing we needed some properties to trigger the evaluation of another property without it getting set itself. Saves use from using try or conditional statements everywhere.
Either that or the combination of some sort of :ignore parameter and :eval.
In the works
1. :ignore or :persist parameter
An :ignore parameter to capture but not ultimately set or persist the property in the model is in the works.
2. Depluralize collection names to find fragment
When finding fragment and no :as specified, try finding using non-pluralized name, and if the fragment is not found, try again using pluralized name.
This is to get around all the boilerplate revolving things like
collection :books, as: :book
3. Nested collections need to be set default
As said in other posted issue
Obviously up to you how you decide to go about these. These are features that we are currently using so if you got better ideas or advice on how to implement them that would be good too.
Looking forward to your reply
Cheers
The text was updated successfully, but these errors were encountered:
Hey Nick,
Just letting you know about some features that I've implemented (in a really really ugly way :P), due to time constraints I haven't had a lot of time to look at the code and needed it done asap. I will fix the code up later when I have time and possibly pull-request.
Basically we are trying to use Representable to populate our models by passing in an extremely large and complex JSON/XML document that I cannot mention due to privacy reasons. Just think Enterprise + Legacy scale :P.
Please find some time to look at our fork (Locomote).
After you've vented about how bad my code is :P, hopefully you can think of much better ways of implementing features that cater to the same requirements if that is in your interest. :)
1. Post-processing
after
hook and:eval
parameterDue to the complex nature of the document we are passing in, we needed a way to build relationships up between objects post-process.
The current params like parse-strategy, required too much boilerplate for what we wanted to do, we needed something more simple and needed to use it for almost half the properties.
The after hook is a method->block that is called as a last resort for linking objects together and doing post-processing on an object.
Example:
The eval hook is done specifically in context of the property, also post-process.
Better example and reasoning is shown in the next section.
2.
parent
attributeChild collections and properties can access the parent representer object during post-process. Again this is due to the "spidery" nature of the documents we receive, we need to re-arrange everything into something that actually looks organised.
We literally get documents where should-be nested objects are instead in a what-is-this-i-don't-even random location. Not only this, but we have to access these objects in order to link other randomly placed objects together.
I shit you not this is what its like (replace theme with what we are actually dealing with)
Multiply this x10 and now you know why the current features require too much boilerplate for what we want to do. :P
3. Default class
We didn't want to have to declare
class: OpenStruct
for every... single... collection for which we have about 20 or so and possibly more in the future. Setting a default class in the Config would be nice.Example:
Is the same as
4. Magic Class instantiation
For the same reason as above, we have lots of collections. We have Representable automagically find which Representable it belongs to. Kind of like how some Ruby database gems do it.
Example:
Is the same as
This behaviour however does not happen if the collection is inlined as a matter of design.
5. Type-cast on parse (symbol or class constant)
We want to be able to use symbols because of the auto-load nature of rails but also we wanted the type casting to happen immediately and not during render.
Example:
6. Always return [] and force conversion to array for collections
Due to the inconsistent nature of the documents we are receiving we needed collections to always return [] if the fragment doesn't exist and always be parsed/set as an array, no matter what even if it is sent in as a singular (even in JSON).
Single items are wrapped in [] before being parsed if Representable knows it should be a collection.
7.
:set
parameterDuring parsing we needed some properties to trigger the evaluation of another property without it getting set itself. Saves use from using
try
or conditional statements everywhere.Either that or the combination of some sort of
:ignore
parameter and:eval
.In the works
1.
:ignore
or:persist
parameterAn
:ignore
parameter to capture but not ultimately set or persist the property in the model is in the works.2. Depluralize collection names to find fragment
When finding fragment and no
:as
specified, try finding using non-pluralized name, and if the fragment is not found, try again using pluralized name.This is to get around all the boilerplate revolving things like
3. Nested collections need to be set default
As said in other posted issue
Obviously up to you how you decide to go about these. These are features that we are currently using so if you got better ideas or advice on how to implement them that would be good too.
Looking forward to your reply
Cheers
The text was updated successfully, but these errors were encountered: