shigechi-64's diary

自由・自主・自立・自尊

LaravelアプリケーションをHerokuにデプロイ後、謎のエラーに苦しんだ話

結論

Laravelで作ったアプリケーションは/vendor以下がデフォルトで.gitignoreに含まれている為、gitリポジトリに変更が反映されない。

従って、/vendor下のファイルに修正を加えた場合、シンプルにHerokuにデプロイしただけではHerokuアプリにはその変更は反映されていない。

Heroku側で直接そのファイルを修正する方法を模索したがうまくいかなかった為、結局/vendor以下を.gitignoreから外してリポジトリに含めるようにしたところ、エラーが解消されたという話。

そもそもの問題

ログインページだけを作ってとりあえずHerokuにデプロイして動作確認をしようとしたら、

The email field is required.

と言われる。これはログイン時にメールアドレスが空のままログインボタンを押した場合に出力されるメッセージで、Laravelにデフォルトで実装されているものである。どうもpostLogin時のバリデーションで引っかかっているみたいだけど開発環境では問題なし。むむむ。

DBを開発環境と合わせてみた

特に何の根拠もなく開発環境と本番でDBが違うのがだめなのか?と思ってHeroku側で使うDBをPostgreSQLからMySQLに変更してみた(Herokuアプリの作成からやり直した)。

本当に何の根拠もなかったけど違うとこってそこしかないやろーとこのときは思っていました。この過程で「開発・本番等価」という考え方を知る。エラーが解消するかどうかは別にして、開発と本番でDBを同じにしてバチはあたるまい。

sizukutamago.hatenablog.com

まあ結果エラー解消しなかったんですが。がびーん。

postLogin時の流れを深掘り

最初からこれをやれば良かったんですが、ログイン処理中のどこでこのエラーが吐かれるのかを追跡してみる。まずはルーティングから。

routes.php

// ログイン認証
Route::get('login', 'Auth\AuthController@getLogin')->name('login.get');
Route::post('login', 'Auth\AuthController@postLogin')->name('login.post');
Route::get('logout', 'Auth\AuthController@getLogout')->name('logout.get');

AuthControllerのpostLoginアクションに飛びます。でもpostLoginアクションの実体はAuthControllerにはなく、
/vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
に含まれているようです。

AuthenticatesUsers.php

・
・
public function postLogin(Request $request)
{
        $this->validate($request, [
            $this->loginUsername() => 'required', 'password' => 'required',
        ]);
・
・

うーんここは怪しい雰囲気です。passwordがrequiredなのはいい。loginUsername()っていうのが超あやしい。

なぜかというと今回、Laravelの標準で用意されているusersテーブルのマイグレーションファイルをそのまま使ってはいないからです。具体的には、標準だと「email」になっているカラムのカラム名を「member_id」に変更しているのです。

なんかその辺が原因なんじゃないかなーと思いつつ同じファイル内にあるloginUsername()を見てみる。

・
・
public function loginUsername()
{
        return property_exists($this, 'username') ? $this->username : 'email';
}
・
・

んーこれっぽいです。この関数はその名の通りユーザ名を返すのだろうけど、最初に設定されているのが「email」なのだな。でもそんなカラム名はないので前掲のエラーとなって現れるということのような気がする。

ということはここを「member_id」に変えてやればうまくいきそう。でもこれ開発時に既出の問題で、ちゃんと直したはずなんだけど・・・

/vendor以下は無視される

ローカルリポジトリではエラーが出ないので、リモートではどうなっているのかと思いGithubでソースを確認しようとしたところ・・・/vendorディレクトリが存在しない!

どうやらLaravelではデフォルトで/vendorディレクトリが.gitignoreに含まれており、リポジトリには含まれないようになっているみたい。よくわからないのですが環境ごとに用意してねってことのようです。

https://qiita.com/zaburo/items/bc448a9fbf2d35194302qiita.com

Heroku側で直接ファイル編集したらよくね?

リポジトリには含まれていないけど、Heroku側にも必ずこのファイルはあるはずなので、じゃあそれを直接修正したらよさそうねってことでheroku run bashして/vendor/laravel/framework/src/Illuminate/Foundation/Authに移動。

それからAuthenticatesUsers.phpvimかなんかで編集っと・・・あれれvimがない?てかどうやって編集したらいいの?nano?わかりません。いろいろ調べてみたけどよくわからず、同じように悩んでいる人はStackOverflowで見つけた。

stackoverflow.com

なんかheroku-vimっていうプラグインを入れればvimが使えるようになるっぽいけどどうもうまく入れられない。↑でもそういう人いますね。んーどうしようと思ってたら同じ記事に以下の回答が・・・

gyazo.com

なんかすごい回りくどいけど確かにこの方法でもできそう。よし、やってみよう!てことでGistにAuthenticatesUsers.phpを登録して該当箇所を修正、Heroku側からwgetでファイルを取得。できた!なんかもっと簡単な方法絶対あると思うけどとりあえずこれでいってみよう!と満足してこの日は作業終了しました。

編集がリセットされる??

よーし、これで大丈夫なはずだぞーと思って再度動作確認。・・・あれ、直ってないけど・・・なんで?

もう一度/vendor/laravel/framework/src/Illuminate/Foundation/Authに移動してファイルのタイムスタンプを確認してみると、修正していないファイルと同じタイムスタンプになっている。なんでやー!

調べてみるとどうもHerokuではgitを経由しないファイルの書き換えはリセットされてしまうらしい。どこで見た情報かはちょっと忘れました。

/vendor以下もリポジトリに含めてしまう

なんかお作法的にはだめっぽいけどもういいやと思って/vendor以下もリポジトリに含めることにしました。結果、無事修正が反映されてエラーは出なくなりました。

デフォルトのUsersマイグレーションをいじらなければ/vendor以下を修正する必要もなかったかもと思ったけど、これからたぶんいじらないといけない場面も出てくると思うんだよなー。どうするのが正しかったんだろう・・・よくわかりませんがとりあえず今の自分にできるのはこれが精一杯でした。

あまり時間もかけていられないのでとりあえずこの方法で行きたいと思います。こういう純粋なプログラミング以外のことではまるのってけっこうストレスですけどひとつひとつ解決していくしかないですね。