This page looks best with JavaScript enabled

【Rails】Zeitwerkの名前空間の競合を無視する

 ·  ☕ 2 分で読めます
✏️

環境

  • Ruby 3.0.2
  • Rails 6.1.4

エラー文

gem 'config'でbundle installをして、意気揚々とrails g config:installしたところ、以下のようなエラーが。

/Users/k_end/runteq/fledge-hub/vendor/bundle/ruby/3.0.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:558:in `rescue in block in set_autoloads_in_dir': private method `autoload?' called for #<Config::Options>
Did you mean?  autoload_rel inferred by Module from file

  /Users/k_end/runteq/fledge-hub/app/controllers/settings/application_controller.rb

Possible ways to address this:

  * Tell Zeitwerk to ignore this particular file.
  * Tell Zeitwerk to ignore one of its parent directories.
  * Rename the file to comply with the naming conventions.
  * Modify the inflector to handle this case.
 inferred by Module from directory

  /Users/k_end/runteq/fledge-hub/app/controllers/settings

Possible ways to address this:

  * Tell Zeitwerk to ignore this particular directory.
  * Tell Zeitwerk to ignore one of its parent directories.
  * Rename the directory to comply with the naming conventions.
  * Modify the inflector to handle this case.
 (Zeitwerk::NameError)
        from /Users/k_end/runteq/fledge-hub/vendor/bundle/ruby/3.0.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:534:in `block in set_autoloads_in_dir'
        from /Users/k_end/runteq/fledge-hub/vendor/bundle/ruby/3.0.0/gems/zeitwerk-2.4.2/lib/zeitwerk/loader.rb:733:in `block in ls'
...

原因

ざっくり言うと、「名前空間がかぶっているからどうにかしてくれよな」という意味。

今回は、/settings/accountというURLを使うために、以下のようなルーティングにしていました。

1
2
3
4
5
Rails.application.routes.draw do
  namespace :settings do
    resource :account, only: %i[show update]
  end
end

そのため、Settings::AccountsControllerが存在していました。
config gemも同様にSettingsモジュールを使うので、これが競合してしまいます。

対処法

エラー文に書いてくれていますが、

  • 特定ファイルを無視するようにする
  • 特定ディレクトリを無視するようにする
  • 競合している名前を変更する
  • ディレクトリ構成から自動推察する単数形・複数形を変更する

app/controllers/settingsディレクトリは今後も増えるので、2番目の特定ディレクトリを無視するようにします。

1
2
3
4
5
6
7
module FledgeHub
  class Application < Rails::Application
    ...
  end
end

Rails.autoloaders.main.ignore(Rails.root.join('app/controllers/settings'))

こんな感じです。
ちなみに、

1
2
3
4
5
module FledgeHub
  class Application < Rails::Application
    Rails.autoloaders.main.ignore(Rails.root.join('app/controllers/settings'))
  end
end

でも問題ありません。
(なんとなく、Rails本体に変更を加えているので、moduleの外に記述している)

参考

ruby - How to ignore a folder in Zeitwerk for Rails 6? - Stack Overflow

別の対処法

以下のファイルを変えることで、Settingsを別の名前にすることもできる。

1
2
3
4
5
Config.setup do |config|
  # Name of the constant exposing loaded settings
  config.const_name = 'Settings'
  ...
end
Share on

END
END
@aiandrox

目次