はじめに
この記事では、以下の方針で画像のアップロード先を分岐する方法について解説しています。
- 開発環境:ローカル(storage/app/public/)
- 本番環境:Amazon S3
事前準備
AWSに未登録の場合は以下を参考にして登録してください。
AWS アカウント作成の流れ | AWS
IAM/S3が未作成の場合は以下を参考にして作成してください。
また、本番環境のアップロード方法で必要になるので、Laravelの実装も行ってください。
超簡単!LaravelでS3を利用する手順 - Qiita
Amazon S3へのアップロードができない場合は、以下の記事を参照してください。
【Laravel】Amazon S3へのアップロードが「403 Access Denied」で失敗する原因と対処方法 - AUTOVICE
アップロード先の分岐方法
実装
アップロードの実装を以下のように変更します。
public function store(Request $request)
{
$post = new Post();
# 画像ファイルのアップロード
$image = $request->file('image');
if ( app()->isLocal() || app()->runningUnitTests() ) {
# 開発環境
$path = $image->store('public/images');
$post->image = Storage::url($path);
}
else {
# 本番環境
$path = Storage::disk('s3')->put('/', $image, 'public');
$post->image = Storage::disk('s3')->url($path);
}
Auth::user()->posts()->save($post);
return redirect()->route('posts.index');
}
解説
開発環境もしくはテスト環境の場合は画像をローカルに保存し、それ以外、つまり本番環境の場合はS3に保存しています。
app()->isLocal()
メソッドなどは以下の設定ファイルを見て判断しています。config/app.php
の42行目あたりに以下の設定があります。
'env' => env('APP_ENV', 'production'),
.env
のAPP_ENV
を参照しています。.env
は以下のようになっています。
APP_ENV=local
local
に設定されています。つまり、.env
ファイルがあるローカル環境では開発環境であるということになります。
では、本番環境ではどうなるでしょうか。
例としてHerokuにデプロイしたとします。Heroku(に限りませんが)には機密情報を含んだ.env
はデプロイされません。そのため、Herokuに環境変数を設定するときはheroku config:set XXXXX=XXXXX
といったコマンドを手動で実行する必要があります。つまり、.env
がなく、環境変数を手動で登録していない限り、APP_ENV
はないことになります。
もう一度config/app.php
を見てみます。
'env' => env('APP_ENV', 'production'),
APP_ENV
が参照できない場合、第2引数のproduction
が適用され、本番環境になるというわけです。
一応、本当にそうなっているか確認してみます。ターミナルで以下のコマンドを実行します。
$ heroku run php artisan tinker
>>> config('app.env');
=> "production"
heroku run
コマンドは、この跡に続くコマンドをHeroku上で実行するコマンドです。つまり、HerokuにデプロイしたLaravelプロジェクトにアクセスしています。
想定通り、本番環境になっていました。もちろん、HerokuにAPP_ENV
は設定していません。
アップロードしたファイルを削除する方法
開発環境の場合はローカルにあるファイルを削除し、本番環境の場合はS3にあるファイルを削除します。
public function destroy(Post $post)
{
Post::destroy($post->id);
if ( app()->isLocal() || app()->runningUnitTests() ) {
Storage::delete('public/images/' . basename($post->image));
}
else {
Storage::disk('s3')->delete(basename($post->image));
}
return redirect()->route('posts.index');
}
アップロードの処理と同様、条件分岐で開発環境と本番環境で処理を分けています。delete
メソッドはディレクトリ名まで含めて指定する必要があるのでご注意ください。
まとめ
Ruby on RailsのActive Storageは、ロジックで分岐しなくても環境によってアップロード先を判断してくれましたが、Laravelはこのようにロジックとして実装する必要があります。
Ruby on Railsは実装する上で楽ではありましたが、ロジックがブラックボックスに隠れてしまっていて、初めのうちは把握しづらいというデメリットがあります。
個人的にはLaravelのほうがわかりやすいかなと思います。