Rails プロジェクトの初期構築

Rails で新規開発を行う場合の、初期構築の手順をまとめます。

# 環境

- macOS Catalina 10.15.6
- Ruby 2.7.1
- Ruby on Rails 6.0.3.2
- VSCode 1.47.2

# Ruby と Rails のバージョンを最新にする

公式サイトによると、現在（2020/7/23）の

- Ruby の安定版は `2.7.1`
    - https://www.ruby-lang.org/ja/downloads/
- Rails の最新版は `6.0.3.2`
    - http://rubyonrails.org/

アップデート方法については [macOS Sierra の Rails 環境をアップデートする \- Qiita](https://qiita.com/mokuo/items/156c35320ec97237c511) を参照

# rails new する

```bash
% cd /path/to/projects
% rails _6.0.3.2_ new some-project -B -T --skip-turbolinks -d mysql
```

- `-B` : rails new 時に bundle install を実行しない
- `-T` : minitest 関連のファイルを作成しない
- `-d` : デフォルトのデータベースを指定する

フロントエンドに関しては、例えば React を使うなら、更に `--webpack=react` オプションを付ける。

この時点で、一旦 push しておくと良い。

- 参考
  - [新規Railsプロジェクトの作成手順まとめ \- Qiita](https://qiita.com/yuitnnn/items/b45bba658d86eabdbb26)
  - [rails newするときによく使うオプションと、rails newした後によく行う設定 \- Qiita](https://qiita.com/jun_jun_jun/items/dd260c43387a8e17803d)

# 諸々の設定

```bash
# ブランチを切っておく
% git checkout -b initialize
```

.ruby-version は rails new の時点で 2.7.1 になっていたので、そのまま。
.gitignore に以下を追加しておく

```:.gitignore
# Additional ignore files.
/vendor/bundle
```

# MySQL をインストールしていない場合は、入れておく

mysql2 gem のインストールに必要。

```bash
% brew list | grep mysql    # インストールされているか確認
% brew install mysql        # インストールされていなければ入れる
% brew services start mysql
% brew services list        # 起動確認
% mysql -uroot              # ログインできるか確認
```

エラーが出た場合は、以下も参考

- [MySQL にログインできない](https://qiita.com/mokuo/items/95bda113cc5095a9f769#mysql-%E3%81%AB%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84)
- [mysql2 の bundle install でエラーになる](https://qiita.com/mokuo/items/95bda113cc5095a9f769#mysql2-%E3%81%AE-bundle-install-%E3%81%A7%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AB%E3%81%AA%E3%82%8B)

# 必要な Gem のインストールと設定

Gemfile の、rails new 時点からの変更点は以下

```diff:Gemfile
 gem 'bootsnap', '>= 1.4.2', require: false

 group :development, :test do
-  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
-  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
+  gem 'faker'
+  gem 'factory_bot_rails'
+  gem 'pry-byebug'
+  gem 'rspec-rails', '~> 4.0.1'
 end

 group :development do
@@ -38,7 +40,12 @@ group :development do
   # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
   gem 'spring'
+  gem 'spring-commands-rspec'
+  gem 'spring-commands-rubocop'
   gem 'spring-watcher-listen', '~> 2.0.0'
+
+  gem 'annotate'
+  gem 'guard-rspec', require: false
+  gem 'pry-rails'
 end

 # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
-gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+# gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
```

`vendor/bundle` 以下に `bundle install` する

```bash
% bundle config set path 'vendor/bundle'
% bundle install
```

ここで、一旦コミットしておく。

## Spring の設定

バックグラウンドでプロセスを起動しておくことで、テストやマイグレーション、コマンドなどの実行が早くなる。

```sh
% bundle exec spring binstub --all
* bin/rake: Spring already present
* bin/rspec: Spring already present
* bin/rubocop: generated with Spring
* bin/rails: Spring already present
```

bin/spring, bin/rspec, bin/rubocop が生成され、bin/rails, bin/rake には以下が追記される

```diff
 #!/usr/bin/env ruby
+begin
+  load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+  raise unless e.message.include?('spring')
+end
```

https://github.com/rails/spring

> Spring is a Rails application preloader. It speeds up development by keeping your application running in the background so you don't need to boot it every time you run a test, rake task or migration.

## RSpec まわりの設定

RSpec の設定ファイルを生成

```bash
% bin/rails g rspec:install
Running via Spring preloader in process 95569
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb
```

### Guard::RSpecの設定

`bundle exec guard` でプロセスを立ち上げ、変更があったファイルのみ spec を走らせることができる。

```bash
% bundle exec guard init rspec
```

Gaurdfile が生成される。

### FactoryBot の設定

FactoryBot のメソッドを `FactoryBot.` を付けずに呼び出せるようにする。
例) `FactoryBot.create` => `create` で呼び出せるようになる

```rb:spec/support/factory_bot.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
```

```diff:spec/rails_helper.rb
 # directory. Alternatively, in the individual `*_spec.rb` files, manually
 # require only the support files necessary.
 #
-# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
+Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
```

参考 : https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#rspec

## annotate の設定

```sh
% bin/rails g annotate:install
Running via Spring preloader in process 97493
      create  lib/tasks/auto_annotate_models.rake
```

# ジェネレータとタイムゾーンの設定

ジェネレータで不要なファイルを作成しないようにし、タイムゾーンを東京に設定する。

```diff:application.rb
     # Don't generate system test files.
     config.generators.system_tests = nil
+
+    # Additional config
+    config.generators do |g|
+      g.assets false
+      g.helper false
+      g.jbuilder false
+      g.test_framework :rspec,
+        view_specs: false,
+        routing_specs: false
+    end
+
+    # NOTE: ActiveSupport::TimeWithZone（ActiveRecordも利用）
+    # https://railsguides.jp/configuring.html#%E3%82%A4%E3%83%8B%E3%82%B7%E3%83%A3%E3%83%A9%E3%82%A4%E3%82%B6
+    config.time_zone = "Tokyo"
+    # NOTE: データベースから日付・時刻を取り出した際のタイムゾーン
+    # https://railsguides.jp/configuring.html#active-record%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B
+    config.active_record.default_timezone = :local
   end
 end
```

# [WIP] Linting & Formatting

（Solargraph, rubocop, prettier, lefthook, ...）

```zsh
% bundle exec yard gems
% solargraph config .
% bundle exec solargraph bundle
Documenting rake 13.0.1
Documenting concurrent-ruby 1.1.6
...
```

```diff:.solargraph.yml
exclude:
 - test/**/*
 - vendor/**/*
 - ".bundle/**/*"
-require: []
+require: # NOTE: https://github.com/castwide/solargraph/issues/87
+  - actioncable
+  - actionmailer
+  - actionpack
+  - actionview
+  - activejob
+  - activemodel
+  - activerecord
+  - activestorage
+  - activesupport
 domains: []
 reporters:
 - rubocop
```

```json:.vscode/settings.json
{
    "solargraph.useBundler": true,
    "solargraph.diagnostics": true,
    "solargraph.formatting": true
}
```

さらに `which bundle` で bundle コマンドのパスを調べ、 `solargraph.bundlerPath` に設定しておく。

- 参考
    - [Ruby Solargraph \- Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=castwide.solargraph)
    - [Solargraph and Rails](https://solargraph.org/guides/rails)
    - [VSCodeでRuby Solargraph拡張機能を使ってみた話 \- Qiita](https://qiita.com/hideki0145/items/d6a18095f95d57eebe96)

# エラー解決編

## MySQL にログインできない

```
% mysql -u root
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
```

/usr/loca/var/mysql/ は `brew uninstall mysql` しても残っているので、このディレクトリを削除して、インストールし直す。

```sh
% brew services stop mysql
% rm -rf /usr/local/var/mysql/
% brew uninstall mysql
% brew install mysql
% brew services mysql
% mysql -uroot
```

参考 : [mysqlがどうしても起動しない \- Qiita](https://qiita.com/_natsu_no_yuki_/items/ae4c94187093e4ab3cdc)

## mysql2 の bundle install でエラーになる

```sh
# bundle install の出力
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2
```

以下を追記することで、解消

```diff:.bundle/config
---
BUNDLE_PATH: "vendor/bundle"
+BUNDLE_BUILD__MYSQL2: "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"
```

参考 : [Rails5 gem mysql2 installエラー \- Qiita](https://qiita.com/Yuki-k-lion/items/82a4e0490e9ed38ce545#%E8%A7%A3%E6%B1%BA%E7%AD%96)