I'm currently developing a large custom content management sollution in rails to handle many different content types (models) and their relations.
The whole data model is build upon active record and has features like content importing and exporting plus synchronization with other services (for example mobile sync to push content changes to smartphones).
For these tasks I have many data conversations, meaning on the one side the active record models and on the other side many different and already existing target formats.
For new data formats I can define the structure on my own, what in most cases means, let rails handle it by using the neat marshalling feature
format.html do
render 'show'
end
format.xml do
render xml: { content:@content }
end
format.json do
render json: { content:@content }
end
But in the case when an existing data schema has to be served, several conversations have to be done:
Renaming keys : In the model, every object is identified by an id property but in the target format the objects property is names uid or OBJECT-ID...
Inlining related Objects : Given I have a model called Person that is related with an Address model. When using the Rails xml serialization the Address Object will be omitted or inlined under an tag. In a given target Format the address might have to be inline in the Person object, meaning the following output would be nedded
<person>
<name>Ben</name>
<street>Some Street</street>
<city>Berlin</city>
</person>
Value transformation: a date property might be needed as a unix timestamp instead of a utc string
The naive sollution:
All this transformations could be done by hand whenever they are needed, meaning just put some ruby code that creates the target data structure:
data = {}
Person.all.each do |p|
# rename property
data[:guid] = p.id
data[:name] = p.full_name
# inline relation
data[:street] = p.primary_address.street
data[:city] = p.primary_address.locality
data[:member_since] = p.created_at.format(...)
end
render xml: { persons:data}
Or for xml only transformations builder templates could be used.
While this option is feasible and also flexible, it spreads the conversaion logic through the whole application and makes controllers grow and in a large application this will be bad for maintainability...
What I'm looking for is a schema based transformation for my models. Meaning I somewhere define a mapping from my activerecord model to the target schema (with a ruby dsl, in xml...) and just have to execute a schema conversation whenever I need a certain data format:
data = Article.all
# the parameter is the name of the target schema
converter = ModelConversation.new(:legacy_contact_list)
render xml: { contacts: converter.execute(data) }
So what I'm actually looking for is something similar to xslt but also applicable for json output and powered by ruby.
Any help/ideas or stories how you do your data conversations in rails would be appreciated.
I've been writing XSLT transformations for a few years, and I can only advise against XSLT or "something similar".
Since you have a Ruby application, just use Ruby! I think it already fits your needs.
Regarding your concern:
While this option is feasible and also flexible, it spreads the conversaion logic through the whole application and makes controllers grow and in a large application this will be bad for maintainability...
This would be something under your control. Just treat your converters as any other part of your application and keep code quality high. Your controllers won't grow if you put the conversion logic into the model itself or move it to a library. Refactor your converters to keep them concise.
Looking at your "naive" example
# rename property
data[:guid] = p.id
data[:name] = p.full_name
# inline relation
data[:street] = p.primary_address.street
data[:city] = p.primary_address.locality
data[:member_since] = p.created_at.format(...)
This code basically says that in your target format, id
is called guid
, full_name
is called name
and so on. I doubt you can write this much shorter than in the code you've already given. So I don't see the need for another technology here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With