LaravelでHerokuにデプロイ後、謎のエラーに苦しんだ話

結論

Laravelで作ったアプリケーションは/vendor以下がデフォルトで.gitignoreに含まれている為、gitリポジトリに変更が反映されない。
従って、/vendor下のファイルに修正を加えた場合、シンプルにHerokuにデプロイしただけではHerokuアプリにはその変更は反映されていない。
Heroku側で直接そのファイルを修正する方法を模索したがうまくいかなかった為、結局/vendor以下を.gitignoreから外してリポジトリに含めるようにしたところ、エラーが解消されたという話。

そもそもの問題

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

The email field is required.

と言われる。どうも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
に含まれているようだ。

/vendor/laravel/framework/src/Illuminate/Foundation/Auth/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に含まれており、リポジトリには含まれないようになっているみたい。よくわからんが環境ごとに用意してねってことらしい。

qiita.com

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

リポジトリには含まれていないけど、Heroku側にも必ずこのファイルはあるはずなので、じゃあそれを直接修正したらよさそうねってことでheroku run bashして/vendor/laravel/framework/src/Illuminate/Foundation/Authに移動。んでAuthenticatesUsers.phpvimかなんかで編集っと・・・あれれvimがない?てか何で編集したらいいの?vi?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以下を修正する必要もなかったかもと思ったけど、これからたぶんいじらないといけない場面も出てくると思うんだよなー。どうするのが正しかったんだろう・・・よくわかりませんがとりあえず今の自分にできるのはこれが精一杯でした。あまり時間もかけていられないのでとりあえずこの方法で行きたいと思います。こういう純粋なプログラミング以外のことではまるのってけっこうストレスですけどひとつひとつ解決していくしかないですね。それでは今日はこのへんで。

Laravel5.1の認可機能でユーザの権限管理をしたい

Webアプリケーションにおいてユーザの権限管理をしたい場面というのはよくあると思います。管理者だけに見せたいページや機能とかですね。どうやるのかなーと思っていろいろ調べていました。

公式を読むと、組み込みで用意されている「認証」というのがまずあって(最初から用意されているAuthControllerとかを使うやつ)、それとは別に「認可」ロジックをとりまとめる手段が用意されているのだと。ふむ。

認可 5.1 Laravel

で、こちら↓できれいにまとまっていたのでそのままでうまくいくかと思いきや、5.3と5.1では認可機能の仕様がけっこう違うみたいだったので公式を参考に試してみた。

参考にしたサイト:
Laravel5 でURLベースの権限管理をする方法 | Crane & to.

認可 5.3 Laravel

よくわからんなりに読んでみると、どうもアビリティというのを定義して、コントローラから参照するという形らしい。大規模アプリ向けにポリシーという方法もあるみたいだけどそちらは今回スルーで。

アビリティを定義してみる

アビリティは

app/Providers/AuthServiceProvider.php

で定義する。

public function boot( GateContract $gate )
{
        $this->registerPolicies( $gate );

        //'admin'アビリティを定義
        //levelが60以上のユーザを管理者として認可する
        $gate->define( 'admin', function ( $user ) {
                return $user->level >= 60;
        });
}

↑のように定義することでログイン中のユーザのlevelカラムが60以上かどうか(管理者かどうか)を判定する。(levelカラムがユーザレベルを表すという設計にしています)

コントローラ側の実装

今回はユーザ登録機能を管理者のみに許可したいという前提。routes.phpには下記のようにルーティングを設定している。

// ユーザ登録
Route::get('signup', 'Auth\AuthController@getRegister')->name('signup.get');
Route::post('signup', 'Auth\AuthController@postRegister')->name('signup.post');

このsignup.getというルーティングに管理者以外はアクセスできないようにしたいので、先程定義したadminアビリティをAuthControllerのgetRegisterアクションにて使用する。実際にはgetRegisterアクションはトレイトなので、コードの実体は/vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.phpにある。

RegistersUsers.php

use Gate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
.
.
.
public function getRegister()
{
        if(Gate::denies('admin')){
                abort(403);
        }
        return view('auth.register');
}

上記実装でテストしてみたところ、管理者以外のユーザで403エラーを捕捉できたので一応目的は達成したはず。(エラー画面はちゃんと作り込むとして)これであってるのかどうかよくわからんけど、一応想定の動きをするのでたぶんあってるということにしておきたい。ちげーよバカ、って人がいたら教えろくださいm(__)m

【放送授業】基盤科目(外国語科目)>01英語事始め>Session 3 空間と前置詞

・英語は空間をコンパクトに把握する言語である

・日本語は助詞(いわゆる「てにをは」)の種類が非常に多い。
助詞を使うとその語の役割が明確になるため、語順はそれほど問題にならない。
英語にはそれにあたる言葉がないため、語順が重要になる
(語順が正しくないと語の意味が明確にならない)
英語は最初にWho did what?に答えてしまい、
あとからwhere, when, how, whyを付け加えていく。
英語は次にどういう要素が来るのかが予め決まっている。
(語順が非常に重要)

Tips.

道が下がっていなくても遠ざかっていく方向をdownで、
逆に向かってくる方向をupで示す
  walk down the street - 通りを歩いて行く
  She walked up to me. - 彼女が私に近づいてきた

乗り物に乗るときのinとon
  大きめの公共交通機関の場合、onが普通(船、バス、電車、飛行機など)
  タクシーや車などの小さめの私的な乗り物の場合はin
  (onを使うと車などによじ登っている感じになってしまう)
  「電車に乗り込む」という動作を強調したい場合はget in the trainという
  使い方をすることも稀にある
  自転車やバイクなど中に入れないものは厳密にonを使う必要がある

大学生になった

この春から放送大学に入学し、大学生になった。

理由は学位が取りたいからである。

放送大学教養学部という学部のみなのだが、
教養学部というだけあって分野が幅広く、いろいろと面白そうな科目がある。

しかしながら、できるだけ早く単位を取得して卒業することが目的なので
得意な情報系と英語系を中心に単位修得を目指していく所存。

ここにもノートとして受講の記録を残していきたいと思う。
(あまり時間をかけてもアレなので簡単に)

さてさて。

www.ouj.ac.jp

悪魔召喚プログラム作ってみた

女神転生シリーズに出てくる悪魔召喚プログラムを作ってみた。

といってもただ単に文字列をゆっくり表示させるだけのプログラムです。
真・女神転生のオープニングがかっこよくて好きなので作ってみました。たまに走らせて悦に入っています。

def DSP_init(script)
 script.each{ |c|
  print c
  sleep(0.1)
 }
 64.times{
  print "\n"
  sleep(0.08)
 }
end

DSP_init("RESET:\n\tSEI\n\tCLC\n\tXCE\n\tCLD\n\n\tX16\n\tM8\
\n\n\tLDX\t#1FFFH\n\tTXS\n\n\tSTZ\tNMITIME\n\tLDA\t#BLANKING\
\n\tSTA\tINIDSP\n\n\tBJSR\tATLUS\n\n\t'EL\sELOHIM\sELOHO\sELOHIM\
\sSEBAOTH'\n\t'ELION\sEIECH\sADIER\sEIECH\sADONAI'\n\t'JAH\sSADAI\
\sTETRAGRAMMATON\sSADAI'\n\t'AGIOS\sO\sTHEOS\sISCHIROS\sATHANATOS'\
\n\t'AGLA\sAMEN'\n".chars)

ブラウザで走るようにしてみたいなぁ。


スーファミ 真 女神転生 【OP】

東野圭吾『殺人の門』

読みました。  

けっこう長い話だけど、おもしろかったです。この話にはまっとうな人間が数人しか出て来ず、ほとんどクズか詐欺師です。主人公がささやかな幸せを手に入れそうになると、その幼馴染である倉持が現れて不幸に叩き落すという繰り返しで、次はどんな不幸に見舞われるんだろうと読んでいるこっちが不安になります。

主人公は倉持を殺したいほど憎んでいるのですが、いつも最後の一線で踏み止まってしまいます。それは一体なぜなのか?二人の奇妙な関係が作られていく過程が丁寧かつリアルに描かれていて読みごたえがあります。

殺人の門

殺人の門

 

 

悩むな

ギルガメシュよ、あなたはどこまでさまよい行くのです

あなたの求める生命は見つかることがないでしょう

神々が人間を創られたとき 人間には死を割りふられたのです

生命は自分たちの手のうちに留めおいて

ギルガメシュよ、あなたはあなたの腹を満たしなさい

昼も夜もあなたは楽しむがよい

(中略)

それが人間のなすべきことだからです  

ギルガメシュ叙事詩 (ちくま学芸文庫)

ギルガメシュ叙事詩 (ちくま学芸文庫)