死んでいたので。
concernsという、その他諸々みたいなものを入れておくディレクトリがある。
models/concerns/hoge.rbでmoduleを定義する
#models/concerns/hoge.rb
module Hoge
def hoge
' hoge by concern in models'
end
end
そして、controllers/concerns/hoge.rbでmoduleを定義する。
#controllers/concerns/hoge.rb
module Hoge
def hoge
' hoge by concern in controllers'
end
end
そして、どっかのmodelでHogeをincludeする。
すると直感的には、models/concerns/hoge.rbが読まれてほしい。
つまり以下は
#models/fuga.rb
class Fuga
include Hoge
def hello
"hello" + hoge
end
end
こうなってほしい
> Fuga.new.hello => "hello hoge in concern in models"
しかし、実際は。。。
> Fuga.new.hello => "hello hoge by concern in controllers
controllers/concerns/hoge.rbが呼ばれている。
これは、railsがincludeするときにファイルを探すとき、module名に対応したファイルを探すらしい。その時に、modelsのディレクトリよりもcontrollersを先に読んでしまう。
なので、controller側のhoge.rbを読んで終わってしまう。
この時気をつけなれければならないのは、じゃあcontrollerの方を適当に入れ子にしておけばいいと思うこともあるかもしれない。以下のような感じ。(僕はこれで行けると思ってしまいました)
#controllers/concerns/hoge.rb
module ControllerHoge
module Hoge
def hoge
' hoge by concern in controllers'
end
end
end
するとこんなエラー。
LoadError: Unable to autoload constant Hoge, expected /home/vagrant/src/stocker/app/controllers/concerns/hoge.rb
要するに、railsはcontrollerのconcernでincludeしたmodule名に対応したファイルを見つけると(Hogeに対してhoge.rb) そのファイルを読み込んでしまう。
そこでファイルの中を見てみると、module Hoge がないやでと言われてしまう。というわけだ。
タイトルに出した「死ぬ」はこれ。僕はこれでうわぁぁぁってなってました。
でもこういった感じで同じファイル名を与えたいときはあると思う。
なので、こうすることですっきりした。(つもり)
まず controllers/concerns/somedir を作る。
そしてディレクトリに対応してネームスペースを与える。
#controllers/concerns/somedir
module Somedir::Hoge
def hoge
'hoge by concern in controller'
end
end
そして、Fuga.new.helloを実行。
> Fuga.new.hello => "hello hoge by concern in models"
いやぁ。。。仕様をもっと理解しよう。