Recently, I've upgraded a Rails app that I'm maintaining to Rails 6 RC2 (coming from 5.2.3). So, right after upgrading, I ran the automated tests (RSpec) and the test output gave me lots of deprecation warnings. One of those warnings was:
DEPRECATION WARNING: render file: should be given the absolute path to a file
So I went to the view file that triggered the warning, and made the changes as follows,
Before:
render file: 'devise/sessions/new'
After:
render file: Rails.root.join('app', 'views', 'devise', 'sessions', 'new.html.slim')
I ran the tests again, no output of deprecation warnings was seen. However, after switching to absolute paths, the view is now only rendering plain HTML code but if I remove the .slim
extension, i.e.
render file: Rails.root.join('app', 'views', 'devise', 'sessions', 'new.html')
The corresponding view is rendered properly but now the test will complain about not using absolute paths. Is there a way to fix this or is this a Rails/Slim bug?
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')
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With