Rails bin/setupについて調べた

## はじめに
bin/seupファイル理解のための備忘録です。

## そもそもbin/ディレクトリとは
Railsのアプリ開発時に使用する、実行コマンドを格納しているディレクトリのこと。

## bin/setup
```ruby:./bin/setup
#!/usr/bin/env ruby
require "fileutils"

# path to your application root.
APP_ROOT = File.expand_path("..", __dir__)

def system!(*args)
  system(*args) || abort("\n== Command #{args} failed ==")
end

FileUtils.chdir APP_ROOT do
  # This script is a way to set up or update your development environment automatically.
  # This script is idempotent, so that you can run it at any time and get an expectable outcome.
  # Add necessary setup steps to this file.

  puts "== Installing dependencies =="
  system! "gem install bundler --conservative"
  system("bundle check") || system!("bundle install")

  # puts "\n== Copying sample files =="
  # unless File.exist?("config/database.yml")
  #   FileUtils.cp "config/database.yml.sample", "config/database.yml"
  # end

  puts "\n== Preparing database =="
  system! "bin/rails db:prepare"
  # To avoid error https://github.com/rails/rails/issues/46845
  system! "bin/rails db:environment:set RAILS_ENV=test"

  puts "\n== Removing old logs and tempfiles =="
  system! "bin/rails log:clear tmp:clear"

  puts "\n== Restarting application server =="
  system! "bin/rails restart"
end
```

[Railsガイド](https://railsguides.jp/4_2_release_notes.html)によると、
>これはアプリケーションの初期設定時に設定を自動化するためのコードの置き場所となります。

`./bin/setup`は実行可能なファイルで、開発に必要な処理をまとめて実行できます。

### #!の意味
スクリプトファイルの先頭に、`#!`があるとUNIXはその後に続くコマンドを実行する。
`#!`は「シェバング」(shebang)と呼ばれ、起動するインタプリタを指定できる。
つまり`#!/usr/bin/env ruby`はrubyの形式でファイルを実行するための命令。

### require "fileutils"
FileUtilsモジュールを使用するために"fileutils"ライブラリを読み込んでいる。

### APP_ROOT = File.expand_path("..", \_\_dir\_\_)
+ File.expand_path
「第2引数で指定したディレクトリ」を相対パスの基準にする
\_\_dir\_\_はファイルのディレクトリを指す。
つまりどのディレクトリからこのソースファイルを実行しても、/binの一つ上の階層（＝アプリのルートディレクトリ)で実行されるようになる。

### def system!(*args)
引数に渡されたコマンドを実行し、コマンドが失敗した場合にはプログラムをエラーメッセージ付きで終了する。
```ruby
system(*args) || abort("\n== Command #{args} failed ==")
```
system変数の使い方
```ruby
system(command, options={}) #commandを文字列で指定する
```
abortの使い方
```ruby
abort(message)
```

### FileUtils.chdir APP_ROOT do
+ FileUtils.chdir
カレントディレクトリを変更
+ FileUtils.chdir APP_ROOT do
カレントディレクトリをアプリのルートパスに変更してブロックを実行する。
ブロックを抜けた後は元のディレクトリに戻る。

### system! "gem install bundler --conservative"
例えばgemをインストールする際は依存している他のgemもインストールされたりするが、`--conservative`オプションによってコマンドで指定したgemのみを対象にできる。

### system("bundle check") || system!("bundle install")
+ `system("bundle check")`
Gemfile内の依存性を現在インストールされているGemが満たしているか確認する。
[参考](https://ruby.studio-kingdom.com/bundler/bundle_check/)
+ system!("bundle install")
依存性に問題があればgemをインストールする。

### unless File.exist?("config/database.yml") ~
`config/database.yml`がなければ、

### system! "bin/rails db:prepare"
__DBが存在しない場合__
1. DBを作成する
2. schema.rbを参考にしてテーブルを作成
3. `rails db:seed`を実行する

__DBが存在する場合__
+ `rails db:migrate`を実行する

### `db:setup`との違い
`db:setup`は、DBが元々存在する場合にschema.rbを参考にテーブルを作成し直し、`db:seed`を実行する

### system! "bin/rails db:environment:set RAILS_ENV=test"

rails db:prepareをすると、テストデータベースにar_internal_metadataテーブルの「key:environment, value:development」を保存する。
つまり、テストDBがdevelopment環境として保存されてしまっているため、`rails test`する時などテストDBを使用したい時にエラーが出る。
それを修正するためのコマンド。
+ ar_internal_metadata
環境情報を保持するテーブル。自動的に作成される。
Rails5から追加され、DBを誤って削除してしまうことを防止するためのテーブル。
environmentがproductionの時に、以下のタスクを実行すると例外が発生する。
・db:drop
・db:drop:all
・db:purge
・db:purge:all
・db:purge:test
・db:schema:load

タスクを実行したい時
```ruby
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rails db:drop
```
監視する環境を任意に変更したい時
```ruby:config/application.rb
ActiveRecord::Base.protected_environments = %w(production staging)
```

### system! "bin/rails log:clear tmp:clear"
+ logディレクトリ以下にあるすべての*.logファイルを0バイトに切り詰める
+ tmpディレクトリからキャッシュ、ソケット、スクリーンショットファイルをクリア

### system! "bin/rails restart"
+ アプリを再起動する

## 参考サイト
・[【Rails】binとは何か](https://almonta2021blog.com/%E3%80%90rails%E3%80%91bin%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B/#:~:text=Rails%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E9%96%8B%E7%99%BA%E3%81%A7,%E3%81%A6%E3%81%84%E3%82%8B%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AE%E3%81%93%E3%81%A8%E3%80%82)
[Rails の /bin/setup にある db:prepare はなにをするのか](https://k-koh.hatenablog.com/entry/2020/09/19/082722)
[linux上で動作するスクリプト先頭行に書く「#!…」行の意味は？](https://nrbm-akatsuki.com/142/)
[Rails5でDBに自動生成されるテーブル、"ar_internal_metadata" とは何なのか](https://qiita.com/EastResident/items/53c24340fd322758901f)
[Rails 5に入ったDB破壊系taskの防止処理について](https://www.tumblr.com/y-yagi/142064773890/rails-5%E3%81%AB%E5%85%A5%E3%81%A3%E3%81%9Fdb%E7%A0%B4%E5%A3%8A%E7%B3%BBtask%E3%81%AE%E9%98%B2%E6%AD%A2%E5%87%A6%E7%90%86%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
[RubyのFile.expand_path('相対パス', __FILE__)の意味](https://maeharin.hatenablog.com/entry/20130104/p1)