[rails]task実行時にrake aborted! NameError: uninitialized constant
発生した問題
./bin/rake でtaskを実行すると問題なく実行できる のに、 bundle exec rake でtaskを実行するとrake aborted!になってしまう 、 という現象が発生してハマりました。
結論
:environmentが指定できていなかった 結論としては非常に初歩的なミスだったのですが、:environment自体は記述していたにも関わらずエラーが起きていたので、気づくのに時間がかかってしまいました。
エラーの再現方法
- 検証用のtaskを作成
./bin/rails g task test_task
- 以下を記述
# lib/tasks/test_task.rake
namespace :test_task do
desc "実験用のタスクです"
task :run, :environment do
TestModel.new # 適当なModelを呼び出す
p 'task finished!'
end
end
- taskを実行
./bin/rake test_task:run
"task finished!"
./bin/rakeで実行した場合は問題なく実行できました。 続いて
bundle exec rake test_task:run
rake aborted!
NameError: uninitialized constant TestModel
???
「 :environment も設定しているので問題ないはず 」と思いながら、色々調べて見つけた方法を試していたのですが解決せず。。。
最終的にものすごくしょうもないミスをしていたことに気づきました。
以下が修正後のtaskです。
# lib/tasks/test_task.rake
namespace :test_task do
desc "実験用のタスクです"
task run: :environment do
TestModel.new
p 'task finished!'
end
end
最初のやつとの違いにお気づきでしょうか?
before:
task :run, :environment do
after:
task run: :environment do
↑ここです。
「:environment も設定しているので問題ないはず」という思い込みのせいでハマってしまったのですが、最初のやり方だと :environmentは設定できておらず、引数として扱われてしまっていました 。
以下のようにコードを修正すると
namespace :test_task do
desc "実験用のタスクです"
task :run, :environment do |task, args|
p args
p 'task finished!'
end
end
引数のキーとしてenvironmentが設定されていることが確認できます。
./bin/rake "test_task:run[test]"
{:environment=>"test"}
"task finished!"
task run: :environment と記述することで正しくtaskが実行できるようになりました。
ただ、 bin/rakeの場合は:environmentが設定されていなくてもエラーにならなかったのはなぜでしょうか?
これは bin/rake 内で springが読み込まれていたためモデルデータがプリロードされていた のが原因でした。
#!/usr/bin/env ruby
begin
load File.expand_path("../spring", __FILE__) # <= ここでspringを読み込み
rescue LoadError
end
require_relative '../config/boot'
require 'rake'
Rake.application.run
これはハマりました。。。 思い込みの力は恐ろしいです。
もう同じことにハマらないようにメモを残しておきます。
task作成時は:environmentの指定方法にご注意 ください。
今回の検証内容はruby 2.2.3, Rails 4.2.1で確認しました。