What’s rendering in Rails?
Rendering is the ultimate goal of your Ruby on Rails application. You render a view, usually .html.erb
files, which contain a mix of HMTL & Ruby code.
A view is what the user sees.
It’s the result of all the work your Rails app has to do. Views combine logic, data & view templates to serve the user’s request.
Even returning a JSON response can be considered a view.
That’s why learning everything you can about the rendering system in Rails is important if you don’t want all your work to get wasted.
Rendering in Rails can produce some surprising behavior. So the more you know the better.
Let’s start with the basics!
The Basics of View Rendering
By default, you don’t have to tell Rails to render anything & views will still work as long as everything else is set up correctly.
This is part of “Convention over Configuration”.
How does that work?
Well, Rails makes assumptions, which you may be unaware of.
It saves you work.
But if you don’t know what’s going on it may feel like magic.
That’s where you can get into trouble!
In this particular case, the assumption Rails makes is that you want to render a template with the same name as the controller action that is handling the request.
So if you call BooksController#index
… Rails renders books/index.erb
.
Now:
You can get more control over this rendering.
This allows you to render a different view from the default.
Here’s how:
class BooksController < ApplicationController def index render :listing end end
This renders books/listing.erb
(or .haml
if you're using HAML views).
You can use a string instead of a symbol.
Like this:
render 'shared/buttons'
Rails will render shared/buttons.erb
.
One Thing You Need to Know
Rendering a view associated with another action won't run that action.
In other words, calling render :index
inside create
won't run the index
method.
Why is that important?
Because the instance variables for that view won't be set!
You need to set them yourself.
Example:
def index @users = User.all end # Missing `@users` here will result in an error or an empty index view # You can use `redirect_to` instead, in that case `index` will run def create render :index end
There's a lot more to rendering than this.
Let's keep going!
Different Kinds of Rendering
Besides rendering a template you have other options.
You can:
- Render an HTML string
- Render a plain text string
- Render JSON
Rendering a string can be helpful during development to show some kind of error message if you don't have a proper template to handle errors.
Or if you're not ready to write your view yet for a particular controller action.
Here's an example:
if @user render :show else render plain: "User not found." end
Rendering JSON directly can be used to build a simple API, it's not the best approach but it can help you get started.
Example:
render json: @user
I haven't used render HTML, but if you have a good use for it let me know!
How to Render Partials
Rendering goes beyond controllers.
You can also render views within views.
We call that a partial.
Why would you want to do that?
Cleaner code & code reuse.
If you're using the same form on 3 different pages it may be a good idea to extract it into a partial.
Now when you want to make changes you only have to do it in one place.
Here's an example:
<%= render :form %>
For this to work you need to name your view file starting with an underscore, like _form.erb
, but when you call render
you don't need the underscore.
You'll be able to access instance variables from partials...
But what about local variables?
You can do this:
<%= render :form, message: "Apples Are Good" %>
This gives you access to message
as a local variable in your partial.
Next:
You're going to learn how you to render multiple things with just one render
call!
How to Render Collections
Partials help you render collections without a loop.
Let's say that you're rendering @books
.
You can do this:
<%= render @books %>
This will work if you have a _book.erb
partial & use book
as your variable inside that template.
Example:
# app/views/books/_book.erb<%= image_tag(book.cover) %><%= link_to "Read Book", book %><%= book.title %>
<%= book.author %>
If you need the current book number (for your CSS classes) you can use book_counter
.
Where book_
is the name of your model.
I think collection rendering is one of my favorite Rails features!
Understanding Rails Layouts
When you create a new Rails app it comes with a "layouts" folder under the views folder.
There you'll find the application.html.erb
file.
That's the default layout!
What's a layout?
A layout lets you give your site a consistent look.
It's:
- The menu
- The footer
- Loading of CSS & Javascript files...
Most of the time the default layout is fine.
But what if you want a different layout for a particular page?
You can use the layout
option.
Example:
render :index, layout: 'admin'
You can disable the layout:
render :index, layout: false
And you can set the layout at the controller level.
Like this:
class AdminsController < ApplicationController layout 'admin' end
Rendering Doesn't End an Action
One common point of confusion is thinking that rendering (and redirecting) inside a controller action will stop running any code after it.
You can come in contact with this if you call render
multiple times.
Example:
def create if yellow_fruit? render :bananas end render :apples end
This will result in an error because render :apples
always runs & you can't render twice in the same controller action.
Here's the solution:
def create if yellow_fruit? render :bananas else render :apples end end
Another option could be to use the return
keyword after render
, but for clarity, it's best to avoid middle-of-the-method return
statements whenever possible.
Summary
You've learned about the all-important topic of rendering in Ruby on Rails.
Rendering allows you to return content to the users of your application & it's one of the final steps inside your controller actions. Understanding rendering helps you write better Rails applications.
Now it's your turn, open your editor & practice your coding skills.
Thanks for reading!
Nice post! Simply explained and to the point.
Thanks for reading! 🙂
Like always, good job! clear and clean… One small correction:
To render a partial with local variables you need the full render partial syntax, you have to include the keyword “partial” after “render” to pass the local variables. For example: render partial: “comments/form”, locals: { message: “Hello World”, comment: comment }.
https://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
Regards!