One of my favourite "magical" characteristics of Ruby on Rails is its naming conventions. We don't need to argue about what the name of the database table that will hold information about a widget should be called, it's widgets. Other frameworks, especially really old ones, didn't do that.
Now, Rails is also great at letting you override and tweaks those options, but really, you almost never need to.
This same convention over configuration mindset continues throughout the framework, even to rendering stuff, which is what we are going to be looking at today.
With Rails, when you pull a record from the database, you can simply call <%= render @widget %>
in your view to spit that thing out on the page. But what is it really doing? Well, assuming you haven't changed any defaults, this is going to make a bunch of sane guesses:
- Your
@widget
is an instance of the Widget
class so the partial we are going to use is widgets/_widget
- Your partial will expect a local variable named
widget
This means <%= render @widget %>
is effectively <%= render 'widgets/widget', locals: { widget: @widget } %>
.
That's a lot of extra code that you just don't need. …unless you do.
I frequently view my widgets in different ways, and have different partials for them:
_widget.html.erb
is the full page view
_widget_row.html.erb
will be used in administrative table views
_widget_card.html.erb
will be a concise view for use throughout the site
- and others as is needed
This means I can't use the simple render call, I need to do one with the partial defined: <%= render 'widgets/widget_row', widget: @widget %>
. That's slightly annoying but tolerable. It even works with arrays. Unless you are rendering an array of mixed things: <%= render @things %>
. The problem here is that you need to do a different partial for each instance in the array potentially.
Well, I'm not going to let that stop me. Inspired by dom_id(@widget, :specialization)
I decided to solve my rendering pain. Adding an additional helper gives me a flexible solution that feels like render
and dom_id
had a baby. Introducing polymorphic_render:
The third branch is the workhorse of this method. It will wet the partial path to the normal partial path (widgets/widget
) and append the suffixes to it. It gets the appropriate name of the instance, and it passes all that to the normal render method.
Basically it does all the manual stuff we normally do, but automatically.
This makes feed rendering code so nice. Instead of some nested monstrosity, its just a simple call to <%= polymorphic_render @feed.items, :feed %>
and the correct things/thing_feed
partial will be used.