ruby-on-railsruby-on-rails-6

Rails: Use of absolute path in Rails 6


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?


Solution

  • 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'
    

    (Only in controllers. In views/templates, a single string argument is a shortcut for the partial: option.)

    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')