::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 メッセージから以下の記事を発見して何とか解決した。良かった。