Solutions to Potential Upgrade Problems in Rails 5
Don't be surprised by some of the newest changes in Rails' latest upgrade
Work Equipment Snow Preparations by MTA Photos is licensed under CC BY 2.0
Rails 5 is out! Rails 5 contains hundreds of changes, including new major features like ActionCable, but for the most part, is a drop-in upgrade for existing Rails 4 applications.
The Rails team has provided a fairly comprehensive upgrade guide, but there are some potential upgrade problems that aren’t fully covered.
Autoload vs. Eager Load in production
With Rails 5, autoloading is now completely disabled if config.eager_load = true
. What this means is that if file paths outside of app/
are in your config.autoload_paths
and not in config.eager_load_paths
(for example, lib/
), these files will no longer load in deployed environments.
This bit me on a recent Rails 5 upgrade because as config.eager_load = false
is set in the development and test environments, the test suite was green and the app worked great in development mode. It was only after I deployed the application that problems cropped up, and the code in lib/
was no longer available to the application.
To test if this is the same with your app, temporarily set config.eager_load = true
in config/application.rb
and run the application and its test suite. If you get uninitialized constant errors there are three possible solutions.
Add to eager_load_paths
Adding the non-app
directories to config.eager_load_paths
will fix this problem, but this comes with an important caveat: every Ruby file in these directories will get loaded when the application boots. In my application, lib
was also doubling as a vendor location for a number of external libraries and tools, which led to the application trying to load Ruby files in these tools, which in turn resulted in strange errors regarding missing requires and dependencies.
Re-enable Autoload
Alternatively, you can re-enable the autoload functionality for all environments:
config.enable_dependency_loading = true
This will take the application back to the Rails 4 way of “eager_load
with autoload
fallback”, but do note that this option may eventually itself get deprecated and removed in later versions of Rails.
Move code into app/
A better solution is to move all code the application requires into the app/
directory. Every directory directly under app/
is automatically eager and auto-loaded by Rails, reducing any external custom configuration you may need. I ended up moving the important files in lib
to live under app/lib
which solved all of my problems.
New Deprecation warnings
A new major version of Rails means a new set of deprecation warnings! Rails 5 is the first version of Rails to require Ruby 2.2.2 or later because of one main feature: keyword arguments. Rails APIs are slowly moving over to make heavy use of keyword arguments, and the first major spam of deprecation warnings related to this change can be found in controller tests.
Controller Tests
There are two important changes to Rails controller testing:
assert_template
If your test suite uses assert_template
, or expect(response).to render_template()
, this assertion has been moved out of Rails core and is now available via the gem rails-controller-testing. In case of rspec, you’ll need to upgrade rspec-rails to at least version 3.5.0.
get, post, put, delete
These testing methods will spam test output with deprecation warnings regarding the change to keyword arguments. Where these methods have long been used with multiple ordinal arguments (get(path, params, session, headers)
), these params after path are now expected to be keyword arguments instead: get(path, params: {}, session: {}, headers: {})
.
Depending on how many controller tests are in your test suite, this could be an annoying change, but as a huge fan of keyword arguments, and given how many times I’ve asked “How do I send custom headers into get
?!”, this is a very welcome improvement that will make these tests easier to write and read.
Comments
Thank you very much! That Eager Load change was about to make me go crazy.
Looking for help on a rails 5.0 upgrade. My app uses Mongoid and SymmetricEncryption gems, among others. Working fine on rails 4.0 but under 5.0 letting these two gems float to the latest versions the app fails to load:
Array values in the parameter to
Gem.paths=
are deprecated.Please use a String or nil.
An Array ({“GEM_PATH”=>[“/Users/peterabramowitsch/.rvm/gems/ruby-2.3.2”, “/Users/peterabramowitsch/.rvm/gems/ruby-2.3.2@global”]}) was passed in from bin/rails:3:in
load' /Users/peterabramowitsch/.rvm/gems/ruby-2.3.2/gems/bundler-1.13.6/lib/bundler/runtime.rb:94:in
rescue in block (2 levels) in require’: There was an error while trying to load the gem ‘symmetric-encryption’. (Bundler::GemRequireError)Gem Load Error is: undefined method
option' for Mongoid::Fields:Module Backtrace for gem load error is: /Users/peterabramowitsch/.rvm/gems/ruby-2.3.2/gems/symmetric-encryption-3.8.3/lib/symmetric_encryption/extensions/mongoid/encrypted.rb:90:in
<top (required)>’/Users/peterabramowitsch/.rvm/gems/ruby-2.3.2/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require’
etc etc…..
Any ideas as to where to look?
Hi Jason! Thank you for nice article. It’s really useful.
But to be precise, the config.eager_load option does not disable autoloading. The “config.cache_classes” option disables autoloading.
The config.eager_load option just eagerly loads directories in config.eager_load_paths. If config.cache_classes is false and config.eager_load is true, both eager loading and auto loading are enabled.
The Rails Upgrade Guide document also says that it will be disabled in the “Production environment”. This is because the config.cache_classes option in the Production environment is true.
Thank you for solving my problem.
Thanks for this post. If I want to arrange files in the /app/lib within subdirectories, how to I get those files to autoload? Do I have to keep all files in app/lib?
@Steve As long as you name the classes and modules underneath
app/lib
as you would other directories, Rails auto-loading will find your code just fine.Thank you for clearing this issue
Hey, thanks you so much for the post. It was very useful.