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'
...