You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试目录下使用紧凑模块类写法触发NameError错误的问题咨询

Fixing uninitialized constant Clients with Compact Class Syntax & Zeitwerk

Hey there, let's break down why this is happening and how to fix it—this is a common gotcha with Zeitwerk's autoloading rules!

The Issue Recap

You've got Dry::Validation contracts in test/fixtures/schemas for validating JSON responses. The nested module syntax works perfectly:

module Clients
  class Show < Dry::Validation::Contract
    json do
      required(:id).filled(:string)
      required(:state).filled(:string)
      # ... other validation rules
    end
  end
end

But when you switch to the compact class syntax your Rubocop rules enforce:

class Clients::Show < Dry::Validation::Contract
  json do
    required(:id).filled(:string)
    required(:state).filled(:string)
    # ... other validation rules
  end
end

You get a NameError: uninitialized constant Clients. You tried adding an empty clients.rb module file but no luck, and couldn't find answers in the Zeitwerk docs.

What's Going On Here?

Zeitwerk's autoloader relies strictly on file and directory naming conventions to map files to constants. When you use Clients::Show, two things need to be true:

  1. There's a file that defines the Clients module (typically clients.rb in the parent directory of your show.rb file)
  2. The Show class lives in a clients subdirectory (which you already have: test/fixtures/schemas/clients/show.rb)

The problem with the compact syntax is that Ruby tries to look up the Clients constant right away, before Zeitwerk has had a chance to autoload it from your empty clients.rb file. The nested module Clients; class Show... syntax doesn't have this problem because it creates the Clients module inline if it doesn't already exist.

How to Fix It

Let's walk through the steps to get this working with the compact syntax:

1. Make Sure the Clients Module is Defined & Discoverable

First, confirm your test/fixtures/schemas/clients.rb file exists with the explicit module definition:

module Clients
  # Empty module is fine—we just need Zeitwerk to register this constant
end

2. Add the Schemas Directory to Zeitwerk's Autoload Paths

This is probably why your initial empty clients.rb didn't work: Zeitwerk wasn't scanning the test/fixtures/schemas directory.

In a Rails app, add this to your config/application.rb:

# Add the schemas directory to Zeitwerk's autoload paths
config.autoload_paths << Rails.root.join("test/fixtures/schemas")
# Or if you're using Zeitwerk directly:
Rails.autoloaders.main.push_dir(Rails.root.join("test/fixtures/schemas"))

If this isn't a Rails app, make sure your Zeitwerk loader is configured to include the test/fixtures/schemas path when initializing.

3. Explicitly Require the Module (If Needed)

If you still see the error, you can force the Clients module to load before defining the Show class by adding a require at the top of show.rb:

require_relative "../clients"

class Clients::Show < Dry::Validation::Contract
  # ... your validation rules here
end

Alternative: Dynamically Create the Module

If you don't want to add a require statement, you can check if the Clients module exists and create it if it doesn't:

# Ensure the Clients module exists before defining the class
Clients ||= Module.new

class Clients::Show < Dry::Validation::Contract
  # ... your validation rules here
end

Wrap-Up

The core issue was that Zeitwerk wasn't aware of your clients.rb file because the schemas directory wasn't in its autoload paths. Once you fix that, the compact class syntax will work just like the nested module version.

内容的提问来源于stack exchange,提问作者Luiz E.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 02:29:07