Saturday, July 27, 2013

Models, Controllers and Views

It has taken me a while to get my head around Rails-think for Model-View-Controller. Here are some notes on what I've learned.

Credits:  The testing patterns can be found on the relishapp website.

Rails MVC concept simplified

Web-requests go to a controller.  The controller usually interacts with a model to carry out model-level actions.  Results from those actions are sent to a view.  The view is responsible for returning results in the web-response.

Views

It is very easy to get de-railed (sorry) when writing a view.  HTML templates are filled in using embedded Ruby.  Since it is embedded Ruby, you can write some very expressive code within the view.  Often, one takes a short-cut and places domain-logic in the view code, sometimes without even knowing it.

Views need to stick to the presentation of data and avoid domain logic.  This will become more apparent when one writes tests for views.  If the presentation includes domain logic, you will spend a lot of time writing complex stubs for that domain logic.

My rule-of-thumb is that a view template should only render a single object or a single list of objects.  That is an odd statement as views can support very rich presentations.  The idea is that one should break down a complex presentation into partial views or just partials.  This is to support design-for-test.

As an example, consider a view which presents both a Widget and a Gadget.  That view should have a partial for rendering the widget and a partial for rendering the gadget.  One then tests each partial outside of the main view.

Note:  Even when partials render a single object, one should build a stubbed version of the object in your test code. Otherwise, domain-logic correctness creeps back into the test code.  Stubbing is easy when one is filling in attributes.  It is slightly more tricky when stubbing out an actual method.  One uses the Klass.any_instance.stub pattern.  That pattern is described here.

When testing the main view, one should stub out the rendering of the widget and gadget views.  The relish people provide a good description here.  The technique use stub_template to replace the rendering of a partial template with a stub.  Quite often, the stub merely renders a distinctive string like "Gadget #{@gadget} goes here" where one stubs off the @gadget instance with a string.

Note:  I have to finish writing about models and controllers.

Models

Models are supposed to represent a portion of your overall information model.  For both good and bad, Rails ActiveRecord models are at the persistence layer.  That layer is also known as object-relation mapping (ORM) layer.

No comments:

Post a Comment