Rails offers an easy way to render objects in a view that are automatically associated with their
own partials. With ActiveModel::Conversion, you can quickly build widgets out of classes (models or presenters or other).
In a recent project, we had several little status/info blocks that we wanted to render on a page. Each block required different model data. In the controller, as we started writing code to fetch all the right data and put it together, we quickly realized that things were going to get ugly. We started with something like this:
You can see that as we added more items to put on the page, both the controller and view got bigger and more complex.
What we wanted was two-fold:
The first step is to build some presenters. Following from the above example, we write two simple wrappers (presenters) to nicely prepare our data so it’s easy to access and render by a view.
At this point, we can simplify the way the controller fetches the data by leveraging these presenters
This solves the first issue, but it has not simplified the view. This is where ActiveModel::Conversion
comes in.
By mixing ActiveModel::Conversion
into our presenter classes, they suddenly know how to render themselves.
In both classes, we add:
include ActiveModel::Conversion
This adds the following methods: #to_model
, #to_key
, #to_param
, and #to_partial_path
to our classes. These methods are used by ActionController::Base#render
. We can now render the object directly like so:
render @object
Rails is effectively doing this:
render @object.to_partial_path, :<model name> => @object
where to_partial_path
generates a path that looks like <model names>/_<model name>
Now that we’ve added the mixin, we can update the view:
And to finish it up, we need to add view partials (whose path is going to match to_partial_path
‘s response) for each of the presenter classes.
Now that we’ve got this far, we can do one more refactor:
At this point, the home page will render the two blocks, one showing hot stuff, and one showing recent activity. The partials are (for this example) pretty dumb, but you can imagine fleshing them out to pull from other methods that the presenters could offer.
ActiveModel::Conversion
, the view can be directly tied to a presenter allowing it to act more like a widget that is easily rendered in your application views.Live on Heroku
| Source on Github
I wrote up a quick sample app that shows off this technique. The main page simply pulls a random set of widgets and renders them. The widgets include
and each one is basically a simple model and a view partial.
If you look through the app on github, you can see how things were built. The first four widgets require Javascript to draw the graphs. That’s all included in the partials for those models. The other widgets are wrappers on a thin feed puller and draw the first few (or random) entries from their respective feeds. The main controller, in this case, simply chooses a random array of these widgets and renders them. With each page refresh, you get a new set of widgets. Try it out!
Easily render a ruby class in Rails using ActiveModel::Conversion
.
SuperWidget
ActiveModel::Conversion
app/super_widgets/_super_widget.html.slim
@widget = SuperWidget.new
render @widget