LoginSignup
32
25

More than 5 years have passed since last update.

クラスロード問題ではまる

Posted at

::Bar::Foo というクラスを読み込もうとした時に、 ::Foo::Bar というクラスがいると、名前解決がうまくいかない事がある、という事象。

$ tree app/models
app/models
├── bar
│   └── foo.rb
├── bar.rb
└── foo.rb

$ cat app/models/foo.rb app/models/bar.rb app/models/bar/foo.rb
class Foo
end
class Bar
end
module Bar
  class Foo
  end
end

$ rails c
Loading development environment (Rails 4.0.0.rc2)
2.0.0p195 :001 > Bar::Foo
TypeError: Bar is not a module
        from /Users/koichi/experiment/missing_name_resolution/ponpon/app/models/bar/foo.rb:1:in `<top (required)>'
###### (省略) #####
2.0.0p195 :002 > Bar
 => Bar
2.0.0p195 :003 > Foo
 => Foo
2.0.0p195 :004 > Bar::Foo
(irb):4: warning: toplevel constant Foo referenced by Bar::Foo
 => Foo

解決するには、そもそもの名前空間を設計しなおすか、もしくは initalize あたりで require させる。

conifg/application.rb
require File.expand_path('../boot', __FILE__)

require 'rails/all'

Bundler.require(:default, Rails.env)

module SampleApple
  class Application < Rails::Application
    # 追加
    config.after_initialize do
      require File.join(Rails.root, "app", "models", "bar", "foo")
    end
  end
end

warning が出るだけならいいが、何故かステージング環境で動かしてる時に限って ::Bar::Foo が読み込めなくて落ちたりした。ローカルで production で動かしても、再現せず…
その後、Unicorn が warning を出してることに気付いて、その warning メッセージから以下の記事を発見して何とか解決した。良かった。

ruby - Preventing "warning: toplevel constant B referenced by A::B" with namespaced classes in Rails - Stack Overflow

32
25
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
25