9 comments

[ 3.3 ms ] story [ 34.3 ms ] thread
I think the point is DHH's 2 cents about emails being more like views, thus under responsibility of controllers.
(comment deleted)
There are some things you just can't do at the model level, for example if the email contains a URL dependent on internationalization (ie myapp.com/login or myapp.co.uk/login) the logic is in the controller (you could store the preferred local but this is just an example).

Who does the actual sending via model callbacks/controller actions anymore anyway? It's prime background task material and you should just be shoving it onto a queue.

With a bit of squinting, you can see that writing a file to disk is lot like a view, except delivered over fputs.

And, for that matter, so is pushing data to a database. It's just the app emitting some set of formatted data over some transport mechanism

For any app, data come in and data go out. It's useful to make distinctions among the formats and means of transport, and practical to define views as "That stuff that gets sent to a user agent over HTTP".

Your first example is right: writing to disk can be a view. A model, however, is the canonical representation of your data. In Rails, the database and in-memory stores, together, make up the model, and are inseperable, as they are both considered to be canonical—if one is changed, that change should be considered canonical and replicated through both. To put it another way, all canonical stores of the data should be bijections.

Generally, then, a view is any other representation than the canonical one, of some useful subset of your data. E-mail messages, files, and web pages are all views, as they are all transformations of your model that make it non-canonical (i.e., if a client edits the email, the change should not propagate back to the canonical form.)

Finally, the controller is an arbiter that creates the various views, but, more importantly, is responsible for deciding what data in a modified view (e.g. A POSTed response to a form) should be merged back into the canonical store, and what data should be considered to be in error and discarded.

" A model, however, is the canonical representation of your data. In Rails, the database and in-memory stores, together, make up the model, and are inseperable, as they are both considered to be canonical—if one is changed, that change should be considered canonical and replicated through both. To put it another way, all canonical stores of the data should be bijections."

I've seen way too many examples of model code that uses "virtual attributes" to present a model as having assorted properties that are not present in the database schema. So I don't buy the claim that the model is simply a mirror of the schema, and vice-versa. Sticking to such a privative approach would be crippling. Coupling object and class design to database schema design is a mistake.

More broadly, Rails (like many other Web frameworks) takes a seriously skewed approach to MVC anyways, so it is more useful to just figure out what works best in any given Rails app rather than worry about whether something is technically a "view" or not.

Virtual attributes are perfectly fine, as long as they can be translated back and forth to real attributes with no information loss. Not each "reflection" of the model (e.g. in-memory object, database record) needs to expose the same interface, only to be theoretically capable of exposing it because it "knows" the same underlying data. Views, on the other hand, are lossy, and so you can't guarantee that you can regenerate the original record from a view of it, only from a given reflection of its model.

You're right, though: Rails is practical code that takes practical considerations before theoretical ones (and has been basically bottom-up designed from the start without any regard for what the commonalities between applications "mean," only what they can help achieve.) Still, it's good to understand the theory of MVC-type apps in general, as you can then see how far away a given framework starts you off from "pure MVC," and can then measure drift from there (i.e. it's probably a bad idea if you code such that you're not obeying MVC even as well as the framework will let you.)

You can also do it from Observers, but I tend to agree that doing it from the model, as a callback, seems the cleanest, more idiomatic way.