DEV Community

Nicholas Dill
Nicholas Dill

Posted on • Originally published at testsuite.io

How to Render Plain Text Templates in Ruby on Rails

If you're trying to get your Rails application to return a plain text file, like robots.txt for search engines, here's how you can do it.

If you want a quick solution this will work but I'll cover everything more in-depth and give you more customization below.


Quickest Way to Render a Text File

1. Place your text file in your views directory:

app/views/example/robots.txt

2. Create a route to map the request to your text file:

get '/robots.txt', to: 'example#robots'

3. Add an action to your controller to render this text file:

# app/controllers/example_controller.rb
class ExampleController < ApplicationController
    def robots
        render 'example/robots.txt', layout: false, content_type: 'text/plain'
    end
end
Enter fullscreen mode Exit fullscreen mode

And you're done, this will map any request to example.com/robots.txt to your text file.

Now, if you want more control such as handling other formats or avoiding 404s, read on.


Control How Your Site Handles TXT Files and Formats

1. Create the TXT File

First, you need to add the file to your views directory.

You can change the extension of your file from robots.txt to robots.text.erb in order to avoid having to explicitly render the robots.txt. Rails looks for ERB templates by default.

Depending on the name of your controller, the file should be located at app/views/example/robots.text.erb.

This is where we'll route the request to.


2. Create the Controller Action

If you're new to Rails, the controller is the actual code your server calls when it gets a request.

By default, it runs any code you specify and renders a view with a matching name.

So if we have a controller we named ExampleController, it should be located at app/views/controllers/example_controller.rb. This will ensure it uses our views at app/views/example/....

If all of our files are in the right places and named correctly, this step is really easy.

We just need to create a method in this controller to point to our text file. It can be empty. The name of the method needs to match the name of the file in order to make things easy.

class ExampleController < ApplicationController
    def robots
    end
end
Enter fullscreen mode Exit fullscreen mode

We set up the controller method (also known as an action) so that Rails knows the file to render.

And that's it for the controller. We don't need to run any code so our method can be empty.


3. Create a Route For Your Text File

Lastly, routing. You have a few choices here depending on what behavior you want.

Option 1: Only Support the TXT Extension

If you only want your server to respond to the txt format, you can specify that specifically in your config/routes.rb.

get '/robots.txt', to: 'example#robots'
Enter fullscreen mode Exit fullscreen mode

If you attempt a different format, like example.com/robots, or example.com/robots.json, your server will return a 404 because those aren't defined in your routes.

Requests would have to be exactly example.com/robots.txt.

Options 2: Respond With TXT Regardless of the Requested Format

Another option is to allow all formats but instead of responding with a 404 for unknown formats, we can respond with our TXT anyway.

# config/routes.rb
get '/robots', to: 'example#robots'
Enter fullscreen mode Exit fullscreen mode

With this approach, there is one additional change we need to make to our controller given it now needs to convert all requested formats to respond with our txt file.

# app/controllers/example_controller.rb
class ExampleController < ApplicationController
    def robots
        # Add the line below
        render 'example/robots.text.erb', layout: false, content_type: 'text/plain'
    end
end
Enter fullscreen mode Exit fullscreen mode

This controller action will now render our robots.text.erb file regardless of the format requested. We specify layout: false to avoid rendering the default layout of our other Rails views. And we pass along the content type of text/plain to specify that this is a text file.

Option 3: Handling Multiple Formats

The last option is to support multiple formats, not just return a text file for everything.

For example many people do this with their sitemap, you can view it in HTML, XML, anything.

We can easily support multiple formats, but you must remember to create the template for each supported format in your views directory.

That means if you want to support XML, you need a robots.xml.erb too. Same for HTML, robots.html.erb. (See the full list of supported formats.)

If you set up routing for a format you don't have a template for, you will encounter an error like ActionController::UnknownFormat in Example#robots.

It will tell you this:

Example#robots is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: []

Once we have our templates created for each format, we need to make sure our controller maps each requested format to the template we created.

We do this by calling respond_to and listing each format we want to support.

class ExampleController < ApplicationController
    def robots
        respond_to do |format|
            format.text
            format.html
            format.any { redirect_to '/robots.txt' }
        end
    end
end
Enter fullscreen mode Exit fullscreen mode

Note: The format.any acts as a catchall, like an "else" statement if none of the previous formats matched.

If you don't want this route to return a 404 for any format you can include it and redirect those bad formats to a format you do expect.

In summary, this controller now responds to any format, example.com/robots.txt maps to your robots.text.erb file, example.com/robots maps to the HTML variant at robots.html.erb, and anything else gets redirected to the first example.com/robots.txt endpoint.


All Mimetypes You Can Respond to With Rails

"*/*"                      => :all
"text/plain"               => :text
"text/html"                => :html 
"application/xhtml+xml"    => :html
"text/javascript"          => :js 
"application/javascript"   => :js 
"application/x-javascript" => :js 
"text/calendar"            => :ics   
"text/csv"                 => :csv   
"application/xml"          => :xml 
"text/xml"                 => :xml 
"application/x-xml"        => :xml 
"text/yaml"                => :yaml 
"application/x-yaml"       => :yaml 
"application/rss+xml"      => :rss   
"application/atom+xml"     => :atom  
"application/json"         => :json 
"text/x-json"              => :json
Enter fullscreen mode Exit fullscreen mode

Errors and Troubleshooting

Common errors and the reasons they come up.

Missing Template

ActionView::MissingTemplate (Missing template /robots.text.erb with {:locale=>[:en], :formats=>[:text], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee]}. Searched in:
Enter fullscreen mode Exit fullscreen mode

This means your controller specified a format but you didn't create a template for it. Specifically if you attempted to go to /robots.txt this means you don't have a view for that response at app/views/example/robots.text.erb.

Create the template and it should work. (But scan for any other templates you might have missed while you're at it.)

Unknown Format

ActionController::UnknownFormat (ExampleController#robots is missing a template for this request format and variant.

request.formats: ["text/plain"]
request.variant: []):
Enter fullscreen mode Exit fullscreen mode

This means you received a request with a format that wasn't specified in your controller.

You would get this error if your controller action supports xml and html, but you receive a request with an txt format.

    def robots
        respond_to do |format|
            format.xml
            format.html
        end
    end
Enter fullscreen mode Exit fullscreen mode

Find your controller action and either add the format to your list or specify a catchall with format.any.

Top comments (0)