Also known as decorators, presenters and view objects.
There are a lot of great resources for learning about view models for Rails. They are also known as decorators, presenters and view objects. It is a solid concept that is easier said than done when implementing for the first time.
For this example, I’ve setup the following naming convention.
app/view_models - All of our view models will live here.
<ViewModelName>View - Add the suffix View to all classes.
All view models are composed of the model (or logic you are encaspulating) and the view_context.
What is the view_context and where does it come from? The view_context is an instance of the Rails view class that will give us access to all of the helpers we might need to use such as image_tag, content_tag and url path helpers.
We have access to the view_context inside of controller actions.
At this point our view model does not do anything. We do not have access to any of the product’s attributes yet. We can use ActiveSupport delegation to delegate methods/atrributes to this view model.
Note: Above we are only delegating the :name attribute, but you can delegate any method/attribute defined on product.
Let’s add some logic for determining the default image for a product.
And now let’s add some more complex logic for displaying a price range.
Rendering collections and link references
Now we have a solid foundation to encasuplate any view related logic. However our view model is not ready yet.
Passing in a view model to link_to or render will result in an error.
How do we initialize a collection of view models?
These problems are easily solved by delegating some methods from our product model to our view model.
To enable link_to our view model needs to have to_param and model_name defined.
To enable render @collection our view model needs to have to_partial_path defined.
To initialize a collection of view models we define a class method to map over the passed in collection.
Our Product model inherits from ActiveRecord::Base which already defines these methods for us.
In our controller we setup our view model collection.
And in our view we can call render and use link_to as expected.