Help us understand the problem. What is going on with this article?

Rails における rake タスクの :environment について

More than 1 year has passed since last update.

rails generate task [namespace] [task_name] で rake タスクを生成するとき、デフォルトで以下のようなファイルがされます。

sample.rake
namespace :sample do
  desc "TODO"
  task foo: :environment do
  end

end

この :environment の部分なんなんでしょう?なにか環境変数的なのを読み込んでるんでしょうか?

rake における Prerequisites

いろいろ調べてみると、そもそも rake には Prerequisites といういわば事前タスクを設定する機能があって、 :environment はそれに相当するもののようです。
http://docs.seattlerb.org/rake/doc/rakefile_rdoc.html#label-Tasks+with+Prerequisites

以下のような rake タスクの場合、まず bar が実行されて、その後に foo が実行されます。これが Prerequisites の役割です。

foo.rake
# frozen_string_literal: true

namespace :sample do
  desc 'TODO'
  task foo: :bar do
    puts 'This is a main task.'
  end

  task :bar do
    puts 'This is a prerequisite task.'
  end
end
$ rake sample:foo
This is a prerequisite task.
This is a main task.

Rails のソースコード内にある environment タスクの中身

このことから、何かしら Rails 側で Prerequisites を用意しているだろうと考え、ソースコードを追ってみることにしました。結果、 railties/lib/rails/application.rb の中で :environment タスクを実行していたことが分かりました。中身を少し詳しくみてみます。

railties/lib/rails/application.rb#L509
    def run_tasks_blocks(app) #:nodoc:
      railties.each { |r| r.run_tasks_blocks(app) }
      super
      require "rails/tasks"
      task :environment do
        ActiveSupport.on_load(:before_initialize) { config.eager_load = false }

        require_environment!
      end
    end

https://github.com/rails/rails/blob/master/railties/lib/rails/application.rb#L509

task :environmentのブロック内で呼び出している require_environment! をみてみると、以下のように config/environment.rb を require していることが分かると思います。

railties/lib/rails/application.rb#L335
    def require_environment! #:nodoc:
      environment = paths["config/environment"].existent.first
      require environment if environment
    end

https://github.com/rails/rails/blob/master/railties/lib/rails/application.rb#L335

config/environment.rb の中身を見ると分かりますが、ここでまさに Rails のアプリケーションコードを読み込んでいます。同じ階層の application.rb を require して、 Rails.application.initialize! で初期化しています。

config/environment.rb
# frozen_string_literal: true

# Load the Rails application.
require_relative 'application'

# Initialize the Rails application.
Rails.application.initialize!

environment は Rails のアプリケーションコードを読み込むタスク

冒頭の rake タスクをあらためて見てみると、 foo の前に environment で Rails のアプリケーションコードを読み込んでくれていることが分かります。実際 Rails 側のクラスやモジュールを呼び出すタスクを :environment 抜きで実行するとエラーが起きます。

sample.rake
namespace :sample do
  desc "TODO"
  task foo: :environment do
  end

end

↓↓ User モデルを一つ取り出してその name を出力しようとするも、「そんなモデル知らんがな」と言われてエラーになってしまいます。

sample2.rake
# frozen_string_literal: true

namespace :sample do
  desc 'TODO'
  task :foo do
    user = User.first
    puts "user name: #{user.name}"
  end
end
$ rake sample:foo
rake aborted!
NameError: uninitialized constant User
/usr/local/bundle/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:74:in `block in load_missing_constant'
/usr/local/bundle/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:8:in `without_bootsnap_cache'
/usr/local/bundle/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:74:in `rescue in load_missing_constant'
/usr/local/bundle/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/active_support.rb:56:in `load_missing_constant'
/sample/lib/tasks/sample.rake:6:in `block (2 levels) in <main>'

このことを考えると、手動で rake タスクを作るより rails generate コマンドで行儀よく作った方が思わぬミスは少なくなりそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした