---
title: "Rendering views outside of controllers in Rails 5"
description:
  "Rails 5 allows rendering views outside of controllers. It has many benefits
  like now views can be used in Mailers and other places."
canonical_url: "https://www.bigbinary.com/blog/rendering-views-outside-of-controllers-in-rails-5"
markdown_url: "https://www.bigbinary.com/blog/rendering-views-outside-of-controllers-in-rails-5.md"
---

# Rendering views outside of controllers in Rails 5

Rails 5 allows rendering views outside of controllers. It has many benefits like
now views can be used in Mailers and other places.

- Author: Prathamesh Sonpatki
- Published: January 8, 2016
- Categories: Rails 5, Rails

Rails request-response cycle is very easy to understand. A request hits the app,
a route is matched to a controller action from `routes.rb`, and finally
controller action processes the request and renders HTML or JSON based on the
type of the request.

But sometimes we want to render our HTML or JSON response outside of this
request-response cycle.

For example let's say user is allowed to download PDF version of a report on
web. This can be done using request-response cycle. We also need to send a
weekly report to managers and the email should have the report as an attachment.
Now we need to generate the same PDF but since emails are sent using background
job the request-response cycle is missing.

Rails 5 has this feature baked in.

Let's say we have a `OrdersController` and we want to render individual order
outside of controller.

Fire up `rails console` and execute following command.

```ruby

OrdersController.render :show, assigns: { order: Order.last }

```

This will render `app/views/orders/show.html.erb` with `@order` set to
`Order.last`. Instance variables can be set using `assigns` in the same way we
use them in controller actions. Those instance variables will be passed to the
view that is going to be rendered.

Rendering partials is also possible.

```ruby

OrdersController.render :_form, locals: { order: Order.last }

```

This will render `app/views/orders/_form.html.erb` and will pass `order` as
local variable.

Say I want to render all orders, but in JSON format.

```plaintext

OrdersController.render json: Order.all
# => "[{"id":1, "name":"The Well-Grounded Rubyist", "author":"David A. Black"},
       {"id":2, "name":"Remote: Office not required", "author":"David & Jason"}]

```

Even rendering simple text is possible.

```ruby

>> BooksController.render plain: 'this is awesome!'
  Rendered text template (0.0ms)
# => "this is awesome!"

```

Similar to `text`, we can also use `render file` and `render template`.

### Request environment

A typical web request carries its own environment with it. We usually handle
this environment using `request.env` in controllers. Certain gems like `devise`
depends on `env` hash for information such as warden token.

So when we are rendering outside of controller, we need to make sure that the
rendering happens with correct environment.

Rails provides a default rack environment for this purpose. The default options
used can be accessed through `renderer.defaults`.

```ruby

>> OrdersController.renderer.defaults
=> {:http_host=>"example.org", :https=>false, :method=>"get", :script_name=>"", :input=>""}

```

Internally, Rails will build a new Rack environment based on these options.

## Customizing the environment

We can customize environment using method `renderer`. Let's say that we need
"method as post" and we want "https to be true" for our background job
processing.

```ruby

renderer = ApplicationController.renderer.new(method: 'post', https: true)
# => #<ActionController::Renderer:0x007fdf34453f10 @controller=ApplicationController, @defaults={:http_host=>"example.org", :https=>false, :method=>"get", :script_name=>"", :input=>""}, @env={"HTTP_HOST"=>"example.org", "HTTPS"=>"on", "REQUEST_METHOD"=>"POST", "SCRIPT_NAME"=>"", "rack.input"=>""}>

```

Now that we have our custom `renderer` we can use it to generate view.

```ruby

renderer.render template: 'show', locals: { order: Order.last }

```

Overall this is a nice feature which enables reuse of existing code.

## Links

- [Human page](https://www.bigbinary.com/blog/rendering-views-outside-of-controllers-in-rails-5)
