rubocop-rails icon indicating copy to clipboard operation
rubocop-rails copied to clipboard

Cop idea: Detect outdated `load_defaults` for Rails updates

Open andyw8 opened this issue 3 years ago • 5 comments

The Rails upgrade process can be tricky. When using the rails app:update command, a line will be added to load_defaults corresponding to the previous Rails version. For example if you're upgrading to 6.1, it'll be load_defaults(6.0).

The aim of this is to allow for an incremental upgrade process, so you can gradually address the items in config/initializers/new_framework_defaults.rb, then delete that file, and change load_defaults to match the current Rails version.

The risk is that if you don't fully complete that process, your app may work fine, but you'll drift further and further from the default configuration of a new Rails app. This makes future upgrades more difficult.

I think it's easy to overlook this, and it would be useful to have a cop to highlight this. I'm imagining that a typical Rails upgrade would happen on a branch, and while in progress this cop would raise an issue. Then when the upgrade is complete, and load_defaults is updated, it would pass again.

andyw8 avatar Apr 13 '21 21:04 andyw8

I'm updating a Rails application and exactly that happened, they were updating the gems but removing the load_defaults statement on config/application.rb so they were on the Rails 4.2 defaults without being aware. This might be useful.

vizcay avatar Oct 14 '21 16:10 vizcay

That would be perfect. There's a guideline for this, too https://rails.rubystyle.guide/#config-defaults

pirj avatar Oct 15 '21 12:10 pirj

@vizcay Would you like to contribute such a cop provided necessary guidance?

pirj avatar Oct 15 '21 12:10 pirj

@pirj if you can point me to a cop with a similar implementation I will try to make an stab on it.

vizcay avatar Oct 17 '21 11:10 vizcay

@vizcay I'd suggest adding a cop (there is a rake generator task); set Include in config/default.tml to config/application.rb. To scan through the whole file just once you can use def on_new_investigation (don't forget to call super). Use a node pattern to scan through the whole file:

def_node_matcher? :load_defaults?, "(send (send nil? :config) :load_defaults $float)"

if load_defaults?(processed_source.ast) returns nothing, then it is missing.

And it will also return a float value if config.load_defaults was called. I'm not sure if there is a reliable way to detect the exact Rails version the code is supposed to run against (and if it's always the case). Might be TargetRailsVersion can be used to compare to.

pirj avatar Oct 18 '21 21:10 pirj