I'm coming from a .NET background, where it is a practice to not bind domain/entity models directly to the view in not-so-basic CRUD-ish applications where the view does not directly project entity fields as-is.
I'm wondering what's the practice in RoR, where the default persistence mechanism is ActiveRecord. I would assert that presentation-related info should not be leaked to the entities, not sure though if this is how real RoR heads would do it.
If DTOs/model per view is the approach, how will you do it in Rails?
Some examples: - A view shows a list of invoices, with the number of unique items in one column. - A view shows a list of credit card accounts, where possibly fraudulent transactions are executed. For that, the UI needs to show accounts that have more than one transaction in red.
For both scenarios, The lists don't show all of the fields of the entities, just a few to show in the list (like invoice #, transaction date, name of the account, the amount of the transaction)
For the invoice example, The invoice entity doesn't have a field "No. of line items" mapped on it. The database has not been denormalized for perf reasons and it will be computed during query time using aggregate functions.
For the credit card accounts example, surely the card transaction entity doesn't have a "Show-in-red" or "IsFraudulent" invariant. Yes it may be a business rule, but for this example, that is a presentation concern, so I would like to keep it out of my domain model.
EDIT: A new example:
BusListDTO can be used to show information to the UI, or serialize it as JSON/XML should the need arises.
Without a DTO, the entity/AR will have a lot of members that are not really persisted since the entity evaluates them for every call. Some examples:
Should the Bus entity be involved in a lot of views that does not directly show its shape, you end up with a monolithic AR class. In a large team scenario, this is a maintenance nightmare, where you spend a lot of time communicating what attributes do in specific use-cases and you have devs who use attributes indiscriminately.
Flattened or unattached ActiveRecord models are a bad choice for DTO's. As the name implies, AR objects are meant to be persistence objects, bundled with ALL the functionality to handle data persistence - dynamic finders, validations, observers, callbacks, as in everything - which I'm pretty sure you won't be needing for presentation purposes alone.
What you maybe looking for is a mix of simple Ruby classes and ActiveModel. You can transform any Ruby class to act like ActiveRecord, without having to load all of its functionality and avoid the unnecessary bloat.
Need serialization? Include ActiveModel::Serialization in your class:
You can then implement your own "build_transfer_object" method inside your AR model:
Been pondering on this and here are some of my notes...
answered Mar 09 '10 at 00:47
Everything in RoR is a class, in essence, objects. Hence data transfer objects aren't explicitly needed. Want a field called line_item for the invoices to represent the number of transactions mapped to it? Declare an instance method in the invoice model which may be then be called anywhere you can instantiate an invoice. You can also go ahead and declare an :invalid? method on the invoice model that will simply return true if the invoice_count is greater than 1.
Want to dynamically render different HTML or CSS in relation to your invoice? Use a helper (resource module accessible from the views) method which will read the value of the :invalid method you just made, then rendering the "Red" CSS class should the current invoice being rendered is indeed, invalid.
Based solely on you example, and assuming all Models, Views and Controllers have been set up, rails can render the invoice view with something like:
As for the RoR community not being familiar with Data Transfer objects - I agree, in that we rarely (if ever) use the term. As far as following the spirit of the principle though, any RoR developer worth his oats will already be doing so - keeping data manipulation and other convenience method declarations away from the view, stored in either helpers, libraries, or models.
It's just that DTO's no longer need to be explicitly defined, as the structure of Rails is built around the MVC design principle so tightly that it forces them on you without even introducing what they are.
March 9, 2010 EDIT:
Most if not all of those concerns come from theoretical standpoints, and I believe you're not getting a good idea of what ActiveRecord really is. If you have something specific that you can't get ActiveRecord to do, post it here and I'll be glad to answer. :)
Some specific comments: