Upgrade rails from 5.2 to 6.0
The main things to handle during upgrading API centric application's rails version from 5.2
to 6.0
include configuration tuning and deprecation warnings fixing.
Configurations
- The
dalli_store
is deprecated and can be replaced with rails built-inmem_cache_store
# Change to this in all environment based config files
config.cache_store = :mem_cache_store
- Set defaults to load 6.0 by default but flip some default values to maintain backward compatibility (case by case), for example in
application.rb
file:
config.load_defaults 6.0
# Rails 6 introduces a new autoloader called :zeitwerk, which will cause autoloading problems if any
# of the classes/modules didn't conform to namespace naming conventions and :classic autoloading can
# still be used until upgrading to rails v7.0+ by setting the autoloader to :classic as below example
config.autoloader = :classic
- When overriding default config, be careful of config not taking effect due to wrong execution order of initializers messed by 3rd-party gems for example:
# NOTE: To override defaults, move the defaults from config/initializers/new_framework_defaults_x_x.rb
# here due to some weird issue causing the item from config/initializers/new_framework_defaults_x_x.rb
# not to take effect because of wrong execution order, see: https://github.com/rails/rails/issues/45105
# Override defaults from rails 5.2
# https://guides.rubyonrails.org/configuring.html#default-values-for-target-version-5-2
# By default set to true, this would add "protect_from_forgery: :exception" that breaks APIs endpoints
config.action_controller.default_protect_from_forgery = false
# ...
# Override defaults from rails 6.0:
# https://guides.rubyonrails.org/configuring.html#default-values-for-target-version-6-0
# By default set to true, this would make cookies incompatible between rails 5.x and 6.x versions
# See https://guides.rubyonrails.org/v6.0/upgrading_ruby_on_rails.html#purpose-in-signed-or-encrypted-cookie-is-now-embedded-within-cookies
config.action_dispatch.use_cookies_with_metadata = false
# ...
By setting config.action_controller.default_protect_from_forgery = false
, it addresses an error Can't verify CSRF token authenticity
raised due to API requests not having CSRF token.
However, if we do want protection from rails and just want to skip for some endpoints, there are other options such as:
# add either of below filters to the controller
skip_forgery_protection
skip_before_action :verify_authenticity_token # equivalent to the above as it's an alias
# limit exception strategy on specific actions only
protect_from_forgery with: :exception, only: :create
# totally disable protection (not recommended)
config.action_controller.allow_forgery_protection = false
# use null session to handle requests without CSRF tokens
protect_from_forgery
protect_from_forgery with: :null_session # equivalent to the above as it's the default option
Deprecation warnings
DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead)
Solution: replace
update_attributes
withupdate
andupdate_attributes!
withupdates!
in models and controllers where they are used.
DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
Solution: add
{ case_sensitive: true }
or{ case_sensitive: false }
to align model uniqueness validation with db schema definitions.
DEPRECATION WARNING: `Module#parent` has been renamed to `module_parent`. `parent` is deprecated and will be removed in Rails 6.1.
Solution: follow this post to identify what is causing the warning messages. If it's caused by outdated gems, update to the version with fix. For example, in the
active_model_serializers
gem, its0.9.7
version has the warnings but the0.9.8
version has the fix as the diff shows.
DEPRECATION WARNING: ActionView::Base instances should be constructed with a lookup context, assignments, and a controller.
DEPRECATION WARNING: render file: should be given the absolute path to a file
DEPRECATION WARNING: ActionView::Base instances must implement `compiled_method_container` or use the class method `with_empty_template_cache` for constructing an ActionView::Base instance that has an empty cache.
Solution: update to use new way to render by
ActiveView::Base
outside controller, for example:
def custom_render(opts)
lookup_context = ActionView::LookupContext.new(ActionController::Base.view_paths)
lookup_context.cache = false
context = ActionView::Base.with_empty_template_cache.new(lookup_context, {}, nil)
context.class_eval do
include ApplicationHelper
end
renderer = ActionView::Renderer.new(lookup_context)
renderer.render(context, opts)
end
References
- Upgrading from Rails 5.2 to Rails 6.0
- Cache Invalidation Complexity: Rails 5.2 and Dalli Cache Store
- 【Rails 6】環境を指定してconsoleを起動する際に詰まったポイント
- Rails で CSRF トークンの検証を制御する
- DEPRECATION WARNING: update_attributes is deprecated and will be removed from Rails 6.1 (please, use update instead)
- Rails 6.0で"Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1."という警告が出たときの対処法
- Working with code deprecations in Ruby
- Rendering views outside of controllers in Rails 5
- ActionView を単体で使用する(6.0以降対応)
- Rails: Render view from outside controller
- Rails 6: Use "render template:" instead of "render file:" in app/views/layouts/admin.html.erb
- Introduce Template::File as new render file: · rails/rails@c7820d8