ローカル環境とリモート環境でBasic認証が機能しない件

タイトルの通りである。`rails new`で新規にアプリケーションを立ち上げ、Herokuで最初のデプロイするとこまでは問題なく完遂できたが、その後に環境変数を使用してローカルにBasic認証を導入しようとしたらうまくいかなかった。ダイアログが表示されない。環境変数を使わずに*application_controller.rb*内にユーザー名とパスワードを直接設定しても同じ。[一つ前の自分の記事](https://qiita.com/tsutsumin_pro/items/e5879093b8c557d6aa8e)に載せている内容も含め、考えられるありとあらゆる方法を全て試したが駄目だった...。
また、ローカルによる動作確認後も、今度はリモートで同じくBasic認証のダイアログが表示されなかった。


# 結論
*application_controller.rb*内にBasic認証用の処理を記述しただけで、**継承先のコントローラファイルを何も生成していないのが原因**だった。リモート環境に関して言えば、masterブランチに最新のコミットをプッシュして`heroku config:set`コマンドで設定した環境変数をきちんと反映させれば解決した。


# 前提条件
- macOS Catalina ( 10.15.7 )
- Visual Studio Code.app( 1.59.1 )
- Terminal.app ( 2.10 )
- Rails ( 6.0.4.1 )
- Heroku ( 7.59.0 darwin-x64 node-v12.21.0 )
- Vivaldi.app ( 4.1.2369.21 (Stable channel) x86_64 )

※執筆時のバージョン


# 本題

### ローカル環境での動作確認
ヒントになりそうな[こちらの記事](https://nyakanishi.work/how-to-implement-basic-authentication/)を発見。
>
おや、認証されない。。。
と焦らないでも大丈夫です。
>
今回application_controller.rbに実装したBasic認証を継承しているコントローラはscaffoldで作成したusers_controller.rbのみです。
>
また、定義されているルーティングはRESTfulなusersリソースのみです。
>
上記からBasic認証の挙動を確認出来るのはhttp\://localhost:3000/users/配下のURLのみになります。

言い換えると、*application_controller.rb*に実装したBasic認証を継承しているコントローラが無かったら、どこのURLにアクセスしても、認証されないどころかそもそもBasic認証自体が機能しないのではないだろうかと考えた。そこでひとまず、何でも良いからコントローラファイルを生成して、Basic認証を通すためのパスを設定してみることにした。

```terminal:terminal.app
% rails g controller items index
```
上のコマンドを実行することによって、indexアクション付きコントローラファイル*items_controller.rb*、及びビューファイル*index.html.erb*が自動生成され、ルーティングも自動設定される[^1]。

[^1]: このように、`rails g controller ‘コントローラ名’ ‘アクション名’`というコマンドで、指定したコントローラだけじゃなく、指定したアクションのルーティングを自動設定し、且つそのビューも同時生成してくれる。ただルーティングにresourcesメソッドは使われず、HTTPメソッドとURIパターンのセットで記述されるので、書き直しが必要。

```ruby:app/controllers/items_controller.rb
class ItemsController < ApplicationController
  def index
  end
end
```

```erb:app/views/items/index.html.erb
<h1>Items#index</h1>
<p>Find me in app/views/items/index.html.erb</p>
```

```ruby:config/routes.rb
Rails.application.routes.draw do
  get 'items/index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
```
`rails routes`すると、URIパターンが*/items/index*となっているから、*http\://localhost:3000/items/index*にアクセスしてみる。

![開発環境によるBasic認証１](https://i.gyazo.com/a7e9da4e97dc861ae534822d0884373b.png "http://localhost:3000/items/indexによるBasic認証")

表示された！正しいユーザー名とパスワードを入力して認証にも成功。試しに*http\://localhost:3000*にもアクセスしてみる。

![開発環境によるBasic認証２](https://i.gyazo.com/f083f19c681e9910e205a8d297ebb43b.png "http://localhost:3000によるBasic認証")

いつものハッピーなイラストのデフォルト画面は表示されたが、やはりルートパスに該当するコントローラとアクションを割り当ててないので、Basic認証のダイアログは表示されなかった。
application_◯◯のファイルは、全ての◯◯において共通の処理を記述する。言い換えれば、application_◯◯はそれとはまた別の各〇〇とを組み合わせて使用するので、継承元のapplication_◯◯だけファイルがあっても何の意味もない[^2]？そのためBasic認証も、しっかり*application_controller.rb*に実装のための追記をしていたとしても、継承先のcontrollerファイルが無かったら機能しないのだ。

[^2]: 〇〇に入るのは、controller(コントローラ)だったり、mailer(メーラー)だったり、record(モデル)だったりする。

```ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base  # ApplicationControllerクラス
  before_action :basic_auth

  private
  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == ENV['BASIC_AUTH_USERNAME'] && password == ENV['BASIC_AUTH_PASSWORD']
    end
  end
end
```

```ruby:app/controllers/items_controller.rb
class ItemsController < ApplicationController  # application_controller.rb内のApplicationControllerクラスを継承
  def index
  end
end
```

### リモート環境での動作確認
`git push heroku master`等でHerokuにデプロイした**後**に環境変数を設定したら、一度リモート環境のプロセスを中断しなければならない。`git push heroku master`を実行する度に、処理の中でHerokuが再起動される。そもそも自分は最初の一回しかデプロイしてなく、しかもその後にBasic認証を導入しようとしていたので、*application_controller.rb*の変更も反映されていない状態だった。また、Herokuによる環境変数の設定はmaster以外のブランチ(トピックブランチ)上で行ったので、一旦`git push heroku master`で枝分かれする前のコミットまでプッシュして、その後にトピックブランチ上のコミットをプッシュする。

:::note warn
現行トピックブランチで作業していても、念の為にGitの変更履歴順を考慮してプッシュするのが良さげ。トピックブランチ上のコミットを先にプッシュすると、枝分かれ(トピックブランチ作成)前段階のコミットが反映されない可能性があるからだ(未検証)。チームで開発するなら話は変わってくるけど...
:::

トピックブランチ上のコミットをmasterブランチに反映させる[^3]には、`git push heroku ‘トピックブランチ名’:master`というコマンドになる。

[^3]: Herokuはリモートのmasterブランチにプッシュするコードだけがデプロイされる。それ以外の、トピックブランチにプッシュしても意味が無いようだ。

```terminal:terminal.app
masterブランチ上のコミットをプッシュ
% git push heroku master

Heroku上の環境変数一覧を参照して、Basic認証用の変数の値が正しく設定されていることを確認
% heroku config

トピックブランチ上のコミットをプッシュ
% git push heroku ‘トピックブランチ名’:master
```
これで、リモート環境でもダイアログがきちんと表示され、認証もばっちり成功した！
因みに、Heroku自体のアップデートと、Rubyのバージョンを2.6.7から2.6.8に上げよという警告メッセージが発生したので、このタイミングでこの２つも実行した♪

Basic認証は認証自体は本当にBasicだけど、実装はちょっとHardだったなぁ...まいった


# 参考記事
- [【Ruby on Rails】Basic認証の実装方法](https://nyakanishi.work/how-to-implement-basic-authentication/)
- [master以外のブランチからherokuにpushする方法 - Qiita](https://qiita.com/fujiab/items/ca79dabad06bbd75ba39)
- [Git を使用したデプロイ | Heroku Dev Center](https://devcenter.heroku.com/ja/articles/git)

# 関連投稿記事
- [ローカル環境で環境変数を使ったBasic認証が通らない件 - Qiita](https://qiita.com/tsutsumin_pro/items/e5879093b8c557d6aa8e)
- [Herokuデプロイ奮闘記（前編） - Qiita](https://qiita.com/tsutsumin_pro/items/b68ea5b4b16826a5286c)