0

I'm currently updating a 5.2 Rails project to 6.0, and I have problems with Zeitwerk.

The web application consists of 3 Rails websites (Private, Public and Backoffice) and 1 gem (named kiosk) that contain an engine that contain common parts for the 3 websites.

In Private website:

app/models/editor.rb

# encoding: utf-8
require_kiosk 'Editor'

class Editor
  scope :available_authors, -> { where(role: AUTHOR_ROLES) }
  scope :journalists_with_email, -> { where(role: :journalist).where.not(email: nil) }

  def some_methods
    # some code
  end
end

In kiosk gem :

config/initializers/require_kiosk.rb:

def require_kiosk(clazz)
  require_dependency "#{Kiosk::Engine.root}/app/models/#{clazz.underscore}"
end

app/models/editor.rb

class Editor < ActiveRecord::Base
  # some relations

  # some validations

  scope :redaction, -> { where(role: [:editor_in_chief, :journalist, :stringer]) }
  scope :with_picture, -> { where("picture_file_name is not null") }

  def some_methods
    # some code
  end
end

My changes to switch to zeitwerk :
In Private Website:

In app/models/editor.rb I removed require_kiosk:

# encoding: utf-8

class Editor
  scope :available_authors, -> { where(role: AUTHOR_ROLES) }
  scope :journalists_with_email, -> { where(role: :journalist).where.not(email: nil) }

  def some_methods
    # some code
  end
end

In Kiosk engine:

I deleted the config/initializers/require_kiosk.rb file.

I added Kiosk directories in loader, in lib/kiosk/engine.rb:

# frozen_string_literal: true

require 'zeitwerk'

module Kiosk
  class Engine < ::Rails::Engine
    ...

    ## Zeitwerk config
    loader = Zeitwerk::Loader.new
    loader.push_dir("#{Kiosk::Engine.root}/app/modules")
    loader.push_dir("#{Kiosk::Engine.root}/app/models")
    loader.push_dir("#{Kiosk::Engine.root}/app/presenters")
    loader.push_dir("#{Kiosk::Engine.root}/app/services")
    loader.push_dir("#{Kiosk::Engine.root}/app/enums")
    loader.setup
  end
end

When I launch drails zeitwerk:check, I have this error :

NoMethodError: undefined method `scope' for Editor:Class
/home/mickael/app/app/models/editor.rb:20:in `<class:Editor>'
/home/mickael/app/app/models/editor.rb:6:in `<top (required)>'
/home/mickael/app/.bundle/ruby/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/kernel.rb:30:in `require'
/home/mickael/app/.bundle/ruby/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/kernel.rb:30:in `require'
/home/mickael/app/.bundle/ruby/3.2.0/gems/activesupport-6.0.6.1/lib/active_support/inflector/methods.rb:282:in `const_get'
/home/mickael/app/.bundle/ruby/3.2.0/gems/activesupport-6.0.6.1/lib/active_support/inflector/methods.rb:282:in `block in constantize'
/home/mickael/app/.bundle/ruby/3.2.0/gems/activesupport-6.0.6.1/lib/active_support/inflector/methods.rb:280:in `each'
/home/mickael/app/.bundle/ruby/3.2.0/gems/activesupport-6.0.6.1/lib/active_support/inflector/methods.rb:280:in `inject'
/home/mickael/app/.bundle/ruby/3.2.0/gems/activesupport-6.0.6.1/lib/active_support/inflector/methods.rb:280:in `constantize'
/home/mickael/app/.bundle/ruby/3.2.0/gems/activesupport-6.0.6.1/lib/active_support/dependencies/zeitwerk_integration.rb:19:in `constantize'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise.rb:325:in `get'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/mapping.rb:83:in `to'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/mapping.rb:78:in `modules'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/mapping.rb:95:in `routes'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/mapping.rb:162:in `default_used_route'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/mapping.rb:72:in `initialize'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise.rb:361:in `new'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise.rb:361:in `add_mapping'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/rails/routes.rb:243:in `block in devise_for'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/rails/routes.rb:242:in `each'
/home/mickael/app/.bundle/ruby/3.2.0/gems/devise-4.9.2/lib/devise/rails/routes.rb:242:in `devise_for'
...
Mickael_S
  • 1
  • 1
  • The app model Editor no longer has any way to know it is based on ActiveRecord -- that's why you are getting the error. – dbugger May 22 '23 at 16:53
  • Engines are automatically autoloaded by the autoloaders in the main application, as it happened in `classic`, you should remove that custom loader in `engine.rb`. Your setup is tricky, and it was already tricky, because there are multiple files defining the same constant. Could you please open a ticket in the Rails repository and /cc @fxn to help you with more tools than this little box for comments? – Xavier Noria May 22 '23 at 16:53

0 Answers0