Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RAILS_ENV environment variable causes __FILE__ to be (incorrectly) set to the absolute path of the file in Rails 5.2 #36550

Closed
Fitzsimmons opened this issue Jun 24, 2019 · 8 comments

Comments

@Fitzsimmons
Copy link

__FILE__ is being set to the absolute path of the file when executed by rails runner in Rails 5.2, but only when the environment is manipulated with the RAILS_ENV environment variable. This will cause any script using the if $0 == __FILE__ idiom to not execute. Using a different method to set the rails environment (e.g. rails runner -e produces the expected behavior).

Steps to reproduce

  1. Create a brand new Rails 5.2 project with rails new
  2. Add a file called runner_test.rb with the following content:
    puts "Rails version: #{Rails.version}"
    puts "Rails env: #{Rails.env}"
    puts "$0: #{$0}"
    puts "__FILE__: #{__FILE__}"
  3. Run DISABLE_SPRING=1 RAILS_ENV=production bin/rails runner_test.rb

Expected behavior

The output should look like the output to DISABLE_SPRING=1 bin/rails runner -e production runner_test.rb, which is:

Rails version: 5.2.3
Rails env: production
$0: runner_test.rb
__FILE__: runner_test.rb

Actual behavior

But instead, __FILE__ is set to the absolute path.

Rails version: 5.2.3
Rails env: production
$0: runner_test.rb
__FILE__: /tmp/runner_problem/runner_test.rb

System configuration

Rails version:

5.2.3

Ruby version:
Reproduced on:

  • ruby 2.4.6p354 (2019-04-01 revision 67394) [x86_64-linux]
  • ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
@Fitzsimmons
Copy link
Author

Update: We discovered that we can work around the issue by removing require 'bootsnap/setup' from config/boot.rb.

@rafaelfranca
Copy link
Member

Yes, bootsnap expand all paths to use absolute paths, so __FILE__ will return absolute paths. If you don't like this behavior you can disable the load_path_cache: option on bootsnap https://github.com/Shopify/bootsnap/tree/3f90857f4835e008d7b3f36d87d91e4c953e8bce#usage

@Fitzsimmons
Copy link
Author

Fitzsimmons commented Jun 24, 2019

But why does it only do that when using RAILS_ENV and not when using -e? This violates the Principle of Least Astonishment. In order for bootsnap to be default in Rails, conventions that are potentially affected by it (especially ones as common as guarding against accidental execution with if $0 == __FILE__) should work the same way whether bootsnap is enabled or not and regardless of the technique used to specify the Rails environment.

@rafaelfranca
Copy link
Member

rafaelfranca commented Jun 24, 2019

Bootsnap, in the same way as Rails, follows some conventions. The conventions you are expecting are different of the bootsnap conventions. When the conventions don't work to you, you can configure, which is what I recommended above.

@rafaelfranca
Copy link
Member

Also, this line answer you why RAILS_ENV has effect and -e doesn't to the bootsnap behavior https://github.com/Shopify/bootsnap/blob/3f90857f4835e008d7b3f36d87d91e4c953e8bce/lib/bootsnap/setup.rb#L3

@Fitzsimmons
Copy link
Author

Fitzsimmons commented Jun 24, 2019

Although I would prefer this to be fixed to not change the behavior of how __FILE__ works in vanilla ruby and all previous versions of Rails, maybe it should at least be mentioned in the Changelog and Rails 5.2 upgrade guide? This is a significant gotcha and can trip up people (like us) that recently migrated. (e.g. https://stackoverflow.com/questions/56678683/why-does-if-file-0-not-work-on-heroku-with-rails-5-2)

@rafaelfranca
Copy link
Member

Isn't it already in the changelog as "Added bootsnap by default"? What bootsnap does and behaves is well documented in its README too.

@rafaelfranca
Copy link
Member

Just to make it clear, neither Rails or bootsnap change __FILE__ what happens is that Bootsnap expand every single file passed to Kernel.load, so a Kernel.load 'a' is transformed to Kernel.load '/path/of/a.rb' and becuase of that Ruby changes __FILE__ to be /path/of/a.rb.

For the "why -ebehaves differently,-eset'sENV['RAILS_ENV']afterbootsnap/setupis already loaded, so it has no effect to the behavior of bootsnap. Bootsnap development mode doesn't expand the paths,-e productionsets bootsnap to development mode becauseENV['RAILS_ENV']is not set, whileRAILS_ENV=production` sets bootsnap to production mode.

We could expand the CHANGELOG entry for bootsnap to include what it does so people understand its behavior without having to look to its README. I'm happy to merge a PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants