rails5からrails6にアップデートしてはまったところ

# はじめに

理由ははっきりしてない物もあるけど、テストが通るところまで行ったのでどなたかの役に立つかもしれないのでメモ残してきます。理由が分かってないものはもしかしたらもっとまっとうな解決方法があるかも。

# 参考資料

[Ruby on Rails 6.0 リリースノート](https://railsguides.jp/6_0_release_notes.html)

※とりあえずあんまり読んでません。実行してエラーに対処していった感じです。


# まずやったこと

* Gemfileの`gem 'rails', '~> 5.2'`を`gem 'rails', '~> 6.0'`
* bundle updateを実行
* ~~rails app:updateを実行。~~一旦全てのファイルを上書きする。
* 上記の変更ファイルの差分を見ながらconfig系など必要な記述を戻す。

## 2019年10月25日追記

> rails app:updateを実行。

これを実行して`bin/rails`、`bin/rake`などが上書きされたのですが、何故かそれによって`spring`が効かなくなってました。diffを見ると下記のようにspringに関する記述が丸っと消えていました。

```diff
#!/usr/bin/env ruby
- begin
-   load File.expand_path('../spring', __FILE__)
- rescue LoadError => e
-   raise unless e.message.include?('spring')
- end
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
```

なんか信用ならないのでbinディレクトリは`rails new`してそこから丸っと持ってきてみました。


# 駄目だったところ

## assetsのCSSとJSが読めない

まず私の環境ですがページ固有のCSSやJSは`app/assets/stylesheets|javascripts/controllers`というディレクトリを作り、以下に`コントローラ名/アクション名.scss|js`などのファイルをおいて、以下のように`config/initializers/assets.rb`に書いて読み込んでました。

```rb
# config/initializers/assets.rb

Rails.application.config.assets.precompile += %w[controllers/*]
```

これが読み込めなくなりました。エラーはこんな感じ

```
Asset `controllers/books/staff.css` was not declared to be precompiled in production.
Declare links to your assets in `app/assets/config/manifest.js`.

  //= link controllers/books/staff.css
and restart your server
```

エラー文の通り修正しても動くのですが、`config/initializers/assets.rb`でも動くので、とりあえず今まで通り`config/initializers/assets.rb`でやってみました。ただ、`*`で全部読み込むのが何故か分かりませんが、効きません（ざっくりリリースノートを見た感じなさそうだった）。そこで下記のように強引に？対応しました。

```rb
# config/initializers/assets.rb

[File.join('app', 'assets', 'stylesheets'), File.join('app', 'assets', 'javascripts')].each do |dir|
  Dir.glob("#{dir}/controllers/**/*")
    .select {|p| p =~ /\.(js|css|scss|erb)$/ && p.exclude?('/_') }
    .map {|p| p.gsub(/\.s?(css|js)(\.erb|)$/, '.\1').gsub("#{dir}/", '') }
    .each do |file|
      Rails.application.config.assets.precompile += [file]
    end
end
```

`app/assets/stylesheets|javascripts/controllers`以下のファイルで`_`で始まっていない物を全て`Rails.application.config.assets.precompile`に突っ込んでます。

突っ込む時は

* 拡張しscssをcssに置換し、erbがついていたら外す。
* `app/assets/stylesheets|javascripts`からの相対パスに変更。

という処理をしてるのでちょっと読みづらいです。

## migrationでエラー

これはちょっと特殊な問題で普通の人ははまらないと思いますが、rails6での変更なので一応書いておきます。

create_tableの時にコピペミスして、同じカラムの定義が二行有るところがありました。rails5の時は無視されていましたが6からエラーをはくようになったようです。

```rb
    create_table "work_style", id: :integer, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
      t.bigint "user_id", null: false, unsigned: true
      ...
      t.time "sat_start_time", null: false
      t.integer "sat_hours", null: false, limit: 1, unsigned: true
      t.time "sat_start_time", null: false
      t.integer "sat_hours", null: false, limit: 1, unsigned: true
      ...
      t.index "user_id", unique: true
    end
```

一部を抜粋しましたがこういうのがエラーになるようになりました。

```
rails aborted!
StandardError: An error has occurred, all later migrations canceled:

you can't define an already defined column 'sat_start_time'.
/Users/masamoto/Documents/repos/home/source/sites/book-on-rails/db/migrate/20171119023508_create_tables.rb:260:in `block in change'
/Users/masamoto/Documents/repos/home/source/sites/book-on-rails/db/migrate/20171119023508_create_tables.rb:244:in `change'
bin/rails:4:in `require'
bin/rails:4:in `<main>'

Caused by:
ArgumentError: you can't define an already defined column 'sat_start_time'.
/Users/masamoto/Documents/repos/home/source/sites/book-on-rails/db/migrate/20171119023508_create_tables.rb:260:in `block in change'
/Users/masamoto/Documents/repos/home/source/sites/book-on-rails/db/migrate/20171119023508_create_tables.rb:244:in `change'
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:migrate:reset => db:migrate
(See full trace by running task with --trace)
```

## ControllerSpecのgetでwrong number of arguments

エラーメッセージはこんな感じ。

```
Failure/Error: get :show, params: { locale: :en, user_id: user.id, token: url_login.token }

ActionView::Template::Error:
  wrong number of arguments (given 2, expected 1)
# ./spec/controllers/users/url_logins_controller_spec.rb:22:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# ArgumentError:
#   wrong number of arguments (given 2, expected 1)
#   ./spec/controllers/users/url_logins_controller_spec.rb:22:in `block (3 levels) in <top (required)>'
```

これは[こちらのQiitaの記事](https://qiita.com/ngron/items/9ca7a5194406035cb107#comment-6d75a83b1521e13ae761)が参考になりました。

修正はGemfileでrspec-railsを4系にすれば直ります。betaなんで微妙ですが少しの我慢だと思います。

```diff
- gem "rspec-rails", '~> 3.7'
+ gem "rspec-rails", '~> 4.0.0.beta2'
```



## SCSSでUndefined variable

これはかなり不可解で、原因はrails6と関係ないかもしれないけど5系の時には確かにならなかったので一応載せておきます。

大分省略しますがSCSSがこんな構造になってます。

```
app/assets/stylesheets
├── _application.scss
├── _utilities.scss
├── _variables.scss
└── utilities
    └── borders.scss
```

```scss
// _application.scss
@import 'variables';
@import 'utilities';
```

```scss
// _utilities.scss
@import 'utilities/borders';
```

```scss
// _variables.scss
$bm_border_default_color: #888;
```

```scss
// utilities/borders.scss
.bu-bdb-dotted{
  border-bottom: 1px dotted $bm_border_default_color !important;
}
```

この状態である特定のSeleniumのテストがCircleci上でのみこけました。エラーはこんな感じ。

```
Failure/Error: border-bottom: 1px dotted $bm_border_default_color !important;

ActionView::Template::Error:
  Error: Undefined variable: "$bm-border-default-color".
          on line 11:29 of app/assets/stylesheets/utilities/borders.scss
          from line 3:9 of app/assets/stylesheets/_utilities.scss
  >>   border-bottom: 1px dotted $bm_border_default_color !important;

     ----------------------------^
./app/assets/stylesheets/utilities/borders.scss:11
------------------
--- Caused by: ---
SassC::SyntaxError:
  Error: Undefined variable: "$bm-border-default-color".
          on line 11:29 of app/assets/stylesheets/utilities/borders.scss
          from line 3:9 of app/assets/stylesheets/_utilities.scss
  >>   border-bottom: 1px dotted $bm_border_default_color !important;
  
     ----------------------------^
  ./app/assets/stylesheets/utilities/borders.scss:11
```

不可解なのはローカルでテストを実行すると問題なく通ります。さらにCircleciを`Rerun job with SSH`で実行しSSHでログイン後`bundle exec rspec`するとテストは通ります。buildから実行されるテストのみ必ずこけます。という事情なのでCircleci側の問題の可能性もありますが・・・

全く原因不明なので何から手をつけていいか分からなかったのですが、カン？でこんなことしたら直りました。

```scss
// _utilities.scss
@import 'variables';
@import 'utilities/borders';
```

一番上の`application.scss`でのみ読んでいた`variables.scss`を一つ下の階層でもimportしたら通るようになりました。むううううう・・・気持ち悪い。まあとりあえず通ったので良しとします。

### 2019/10/18 14:55追記

> 不可解なのはローカルでテストを実行すると問題なく通ります。さらにCircleciを`Rerun job with SSH`で実行しSSHでログイン後`bundle exec rspec`するとテストは通ります。

`tmp/cache/assets`を削除するとローカルでも同じエラーが再現することを発見しました。そして、二度目実行すると通ります。`tmp/cache/assets`の中に何かが出来ると通るんですね。こういうのは大抵キャッシュですよね。とりあえず少し進展したのでメモ。

---

まだ大量のワーニングが出てますけど以上でテストは通りました。さて・・これからワーニング消していく作業を頑張ろうと思います。