Home > Enterprise >  Why is Rails/Zeitwerk expecting `burgerfrenchfry_coupon.rb` to define the constant `BurgerFrenchfryC
Why is Rails/Zeitwerk expecting `burgerfrenchfry_coupon.rb` to define the constant `BurgerFrenchfryC

Time:07-21

I'm working on upgrading a large legacy Rails application from 5.2 to 6.0. In the process of fixing the autoload paths, I've run into an issue where Rails/Zeitwerk seem to be breaking their own rules about how the names of constants are defined in relation to their filenames. I can't share actual code from this application, but the situation is essentially this:

In config/application.rb:

config.autoload_paths << "#{config.root}/app/models/coupons"

In app/models/coupons/burgerfrenchfry_coupon.rb:

class BurgerfrenchfryCoupon << ApplicationRecord
end

When another class in the application references the BurgerfrenchfryCoupon class, a NameError is thrown with BurgerFrenchfryCoupon as a suggested classname (that class does not exist in the application). When I require the app/models/coupons/burgerfrenchfry_coupon path directly in the file referencing BurgerfrenchfryCoupon I get a Zeitwerk error: Zeitwerk::NameError: expected file /redacted/app/models/coupons/burgerfrenchfry_coupon.rb to define constant BurgerFrenchfryCoupon, but didn't

I've done a thorough search of the application to find anywhere where the expectation could have been customized and I've come up with nothing. Does anyone have any ideas about the follow:

  1. Why this is happening?
  2. Where or how an override on the constant name expectation might have been made?
  3. How I can configure Rails to recognize that this constant should be defined in this file without changing all of the references to it in the application to BurgerFrenchfryCoupon?

CodePudding user response:

The problem is that, for some reason, the autoloader's inflector is configured to camelize "burgerfrenchfry_coupon" as "BurgerFrenchfryCoupon". If using Active Support inflections (the default), there's some custom inflection rule somewhere that affects this.

You can fix this particular one without affecting the rest of the application by overriding this way:

# config/initializers/autoloading.rb

inflector = Rails.autoloaders.main.inflector
inflector.inflect("burgerfrenchfry_coupon" => "BurgerfrenchfryCoupon")

That sets a special mapping in the autoloader's inflector that ignores everything else.

CodePudding user response:

The answer here ended up being a custom inflection that had been added to activesupport.

ActiveSupport::Inflector.inflections do |inflect|
  inflect.acronym 'BurgerFrenchfry'
end

As this inflection was necessary for other parts of the application, to fix the Zeitwerk error I added the file config/initializers/zeitwerk.rb with the following content:

Rails.autoloaders.each do |autoloader|
  autoloader.inflector.inflect(
    "burgerfrenchfry_coupon" => "BurgerfrenchfryCoupon"
  )
end

Which overrides the inflection for this one file

  • Related