Customizing rails #to_partial_path
Rails is very helpful when it comes to automatically rendering a partial for a given object.
<% @startups.each do |startup| %>
<%= render startup %> <!-- Renders startups/startup partial -->
<% end %>
This loop renders the startups/startup
partial for every startup in the collection. If you want to
change the partial it renders, you can override the #to_partial_path
method on your object like this.
class Startup < ActiveRecord::Base
def to_partial_path
'startups/summary'
end
end
This is great if you want change the partial path for all startup objects in your application. How about if you want to change the partial path only in a specific view?
Overriding #to_partial_path with a decorator
One approach is to use the decorator pattern wrap the model and override only the #to_partial_path method.
class StartupTile < SimpleDelegator
def to_partial_path
'startups/tile'
end
end
StartupTile.new(Startup.new).to_partial_path #=> "startups/tile"
However, it can be very inconvenient to create a new class every time you want to customize an object’s partial path.
There’s a gem for that
We decided to generalize this solution and turn it into the
partial_path_customizer gem. This gem
includes a single method in your view helpers called #customize_partial_path
.
<!-- Renders the "startups/tile" partial -->
<%= render customize_partial_path(startup, 'tile') %>
This code decorates the startup object and overrides #to_partial_path
so it returns startups/tile
.
This also gets useful when you have a collection of multiple types of objects, possibly from a
polymorphic relationship.
# Somewhere in the controller
@employees = [Developer.new, Designer.new, Developer.new]
# Then in the view
<%= render customize\_partial\_path(@employees, 'summary') %>
This renders the developers/summary
, designers/summary
, developers/summary
partials, respectively.
The partial_path_customizer gem solves
the problem of wanting to use Rails implicit rendering, but only being able to use it for one partial
per object. Since this gem only wraps the object being rendered, you can still pass all of normal
options to the #render
that allow you to do things like caching partials.
<%= render customize\_partial\_path(@developers, 'summary'), cache: true %>
If you’d like to learn more about the basics of #to_partial_path
, check out this blog
article: http://robots.thoughtbot.com/rendering-collections-in-rails.
Please send us feedback on Twitter and let us know what you think.
Originally published at blog.animascodelabs.com on October 9, 2014.