Josh Brown

February 9, 2024

Rails: Templates vs Partials, and what even is the difference?

I've been doing some more work on the open source project Maybe, and I've come across an interesting little detail that I hadn't really thought about before.

As we build out our Hotwire powered Rails apps and we extract out little helpers to render things like modals, and other components (especially now we have strict partials from Rails 7.1), we start to get a lot of code that looks like this:

def modal(&block)
    render "shared/modal", &block
end

All is well. We think we're rendering a partial, and why would we not? We've written our `_modal.html.erb` file, and we may have even added the strict locals to the top of it.

Well it turns out everything is a lie. Your perfect little partial is in fact now a template, and everything inside the block will be executed within the context of that template!

If we care about a detail like that, and I'll explain later why you might, then we need to make sure we're rendering a real partial.

Real partials don't accept blocks though. To make your code render as a real partial you'll need to change some things up a bit:

def modal(&block)
    content = capture &block
    render partial: "shared/modal", locals: { content: content }
end

Of course, we'll now also need to update our shared/modal partial to render the content instead of yielding the block to account for this change.

Why even care?

It might not even matter for you, but if you're doing internationalization and using lazy keys then this will have a major effect on how those keys are looked up.

With the former approach, the keys would now all be scoped by our modal template. Now with the updated approach, the keys are as you would expect - scoped by the view of whatever rendered the modal.

Underneath the translation helper uses the @virtual_path variable to determine the current context and template. Which is altered when we render a block in the context of a template.

It's possible this has other effects elsewhere, so if you're having issues it might be worth checking are you rendering a template or a partial?

You can checkout my PR solving this issue in the Maybe repo here maybe-finance/maybe#404.

About Josh Brown

Aspiring polymath; designer, developer, writer, maker, creator, gamer and aviator.

Want to chat? Drop me an email, or follow me on Twitter