bundle exec rake db:migrateって何をしているの？

今までは`rails db:migrate`を使用していましたが、学習する教材によっては

```
bundle exec rake db:migrate
```
としているので、コマンドがどのような意味を持っているのか調べてみました。

## まず、`bundle`ってなに？

`bundler`というGemを利用する際に使うコマンドです。
`bundler`はGemの依存関係を解決するためのGemです。

>　Bundlerは、必要なgemとバージョンを正確に追跡してインストールすることにより、Rubyプロジェクトに一貫した環境を提供します。
　Bundlerは依存関係の地獄からの出口であり、必要なGemが開発、ステージング、およびプロダクションに存在することを保証します。プロジェクトの作業を開始するのは簡単bundle installです。
bundlerの公式HPよりGoogle翻訳　https://bundler.io/

## `exec`とは？
> #####実行  【 execution 】  run / execute / exec / エグゼキューション
　プログラムの実行のことは英語で “execute” （名詞形はexecution）と言い、 “exe” “exec” の略号で示されることもある。
　それ自体がコンピュータ上で実行できる形式のプログラムファイルなどを「実行可能形式」（executable format）「実行可能ファイル」（executable file）などと言う。
　また、プログラムを実行することを “run” （ラン：走る、走らせる）と表現することもあり、プログラムの実行時のことを「ランタイム」（runtime）という。日本語でも同様に「プログラムを走らせる」と言うことがある。
IT用語辞典 e-Words http://e-words.jp/w/%E5%AE%9F%E8%A1%8C.html

## ということは、`bundle exec`の意味は？
`bundle`でコマンドを実行すると宣言している。ということでしょうか。

パーフェクトRubyを見ると、
>`bundle exec`コマンドは`bundle install`でインストールしたディレクトリに対してパスを解決し、コマンドを実行するためのプログラムです。
パーフェクトRuby【改定２版】Rubyサポーターズ著　技術評論社

とあります。

以下のBundler公式HPからの引用と合わせて考えると、`bundle exec`は`bundle install`したディレクトリを常に記憶しているから、installしたGemがどこにあろうが、`bundle exec`しておけば気にしなくていいみたいです。

>　このコマンドを実行することで、Gemfile(5) で指定されたすべてのジェムを Ruby プログラムで要求できるようにします。
　基本的には、通常は rspec spec/my_spec.rb のようなものを実行していて、Gemfile(5) で指定されたジェムを使用したい場合、 bundle install(1) でインストールしたものを bundle exec rspec spec/my_spec.rb を実行する必要があります。
　bundle exec はシェルの $PATH に実行ファイルがある必要はないことに注意してください。
bundlerの公式HPよりDeepL翻訳　https://bundler.io/v2.0/man/bundle-exec.1.html

また、`bundle exec`はrailsプロジェクト内の`Gemfile.lock`で指定された環境で実行されます。
Railsプロジェクト内でver.1
Railsプロジェクト外のグローバルシステムでver.2
の何かのGemを持っていた場合、以下のように実行されます。
`bundle exec`がなければ、実行するGemのバージョンが異なる可能性が出てきます。

|     コマンド  　　|　実行される環境     |  バージョン  |
|:-----------------|:------------------:|:-----------:|
| bundle exec      |Railsプロジェクト    |   Ver.1     |
| bundle execなし  |マシン　             |   Ver.2     |


## `rake`とは
Gemです。Rubyで記述されたビルドツールで、`Rakefile`と呼ばれるファイルに一連の処理をまとめた「タスク」を定義するというかたちで動作を記述します。
なお、ビルドツールとは自動化を想像するといいと思います。
一連の処理を記述したメソッドを実行するのと同じように、Rakeでは定義された「タスク」を実行します。

ちなみにRails5以降なら、`rake`は不要みたいです。

>Rakeとは
説明
Rubyで記述されたビルドツール
Rails5以降はrailsコマンドでrakeを呼び出せるようになっています
Railsドキュメント　https://railsdoc.com/rake

ネットで調べるといつも`rake`は不要という記事が多かったのですが、これで納得しました。
試しにrails6で、`bundle exec rails db:migrate`を実行したら上手くいきました。
しかしrailsコマンドを使用するなら、`bundle exec`はいらないような気がするのですが、どうなのでしょうか。
`bundle exec`を使うと、railsプロジェクト内での環境で実行します。
では、`rails`はrailsプロジェクト内での環境で実行してくれるのでしょうか。
`rails`は、プロジェクトルートの `bin/rails`を優先的に起動する仕様になっています。
そして、`bin/rails`→`config/boot`→`bundler/setup`と読み込み実行されます。
`bundler/setup`が実行されると`bundle exec`と同じ事が行われるので、結果として`rails`だけで十分のようです。
（ただ、私のプロジェクト内にはbundlerディレクトリが見つかりませんでした。）

## `rake db:migrate`とは
`rake`は、`rake タスク名`で実行します。
今回の`db:migrate`のように、`:`があるのは、複数のタスクがあるグループから、特定のタスクを取り出していることを示しています。

```Ruby:Rakefile
namespace :db
  desc "説明文"
  task :migrate do
    処理を記述
  end
end
```

## db:migrateの処理内容は？
Railsドキュメントから。
>未実行のマイグレーションファイルを実行
#### 使い方
```
$ rake db:migrate [VERSION=バージョン番号 オプション]
```
#### 実行の流れ
1 rake db:migrateを実行
2 schema_migrationsテーブルを調べ、存在しなければ作成
3 db/migrateディレクトリ内のすべてのマイグレーションファイルを調べる
4 データベースの現在のバージョンと異なるバージョンがあった場合、データベースに適応
5 schema_migrationsテーブルの更新
Railsドキュメント　https://railsdoc.com/page/rake_db_migrate

## まとめ
　`bundle exec rake db:migrate`とは、インストールしたバージョンのGemを使用するために`bundle exec`し、`rake db:migrate`で決められたタスクを実行している。
　なお、rails5以降では、`rails`コマンドで`bunle exec`と同じ結果が得られる上、`rake`タスクも呼び出せるため、`rails db:migrate`でよさそう。
　間違っていたらすみませんm(__)m

## 参考

Rakeの理解に
http://rubicle.net/rubicle_talk_1-1.html
Bundlerの理解に
https://pikawaka.com/rails/bundler#bundler%E3%81%AE%E7%89%B9%E5%BE%B4