Rails: Use of absolute path in Rails 6

I had this same challenge when working on Rails 6 API-only application.

I wanted to render a static page from a controller called home_controller.rb

Here's my code:

require 'rails/application_controller'

class HomeController < Rails::ApplicationController
  def index
    render file: Rails.root.join('public/index.html')
  end
end

But when I try accessing the page I get the error:

Started GET "/favicon.ico" for ::1 at 2021-02-23 16:25:41 +0100
Processing by HomeController#index as */*
  Parameters: {"other"=>"favicon"}
Completed 500 Internal Server Error in 1ms (ActiveRecord: 0.0ms | Allocations: 301)
 
ArgumentError (`render file:` should be given the absolute path to a file. '/home/my-computer/Projects/MyWebsite/public/index.html' was given instead):

Here's how I solved it:

The issue was that I was missing the file index.html in the directory public, so Rails could not locate it.

All I had to do was to add the file index.html in the directory public. This time when I tested it was fine.

That's all.

I hope this helps


In your case it looks like you want to render a normal view, i.e. a template.

In that case using the file option is not the recommended way. Instead you should be using the template option.

render template: 'devise/sessions/new'

Or even better, you can use this shortcut:

render 'devise/sessions/new'

Background

The file option is intended to render a view which is outside your Rails application, where you can't rely on Rails' view lookup logic. Consequently Rails wants to have an absolute path. Demanding an absolute path also forces the developer to think about relative path segments (/../).

Omitting the .slim extension and then having the file processed by the template engine is a feature intended for templates. Using file seems to provide the very same functionality, but my guess is that this is just a side effect of the internal workings of the view path lookup. It looks like the Rails developers want to improve the distrinction between files and templates in the future and deprecating relative files is an intermediate step to not break too many existing applications which rely on using file and still expect the features of a template.

PS: It is not necessary to manually split your path. So if you for some reason still want to use file with an absolute path, instead of

render file: Rails.root.join('app', 'views', 'devise', 'sessions', 'new.html.slim')

use this

render file: Rails.root.join('app/views/devise/sessions/new.html.slim')