開発環境と本番環境で画像のアップロード先を分岐する方法

はじめに

この記事では、以下の方針で画像のアップロード先を分岐する方法について解説しています。

  • 開発環境:ローカル(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'),

.envAPP_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のほうがわかりやすいかなと思います。

関連記事

開発環境(ローカルストレージ)と本番環境(Amazon S3)にトリミング+リサイズした画像を保存する方法
# はじめに 以前、以下の記事を書きました。 - [開発環境と本番環境で画像のアップロード先を分岐する方法 \- AUTOVICE](https://www.autovice.jp/articles/68) - [ローカルやAmazon [...]
2020年3月7日 11:56
Laravel Mixの仕組みをわかりやすく解説:CSSをSASS/SCSSで記述する方法
# はじめに Laravel Mixの仕組みをわかりやすく解説します。Laravel Mixを使ってアセットコンパイルを行うことで、SASS/SCSSでCSSを記述できるようになります。 # Laravel Mixの仕組み まずはじめに、 [...]
2020年3月6日 9:25
【Laravel 6.x】Laravelプロジェクトの名称を変更する方法
# はじめに あまりないケースではありますが、一度作成したLaravelプロジェクトの名称を変更する方法を解説します。ここで言うLaravelプロジェクトの名称とは、以下のコマンドの`Sample`のことを指します。 ```terminal [...]
2020年3月4日 16:24
【Laravel】ローカルディスクやAmazon S3にアップロードした画像をビューで表示する方法
# はじめに 本記事では、ローカルディスクやAmazon S3にアップロードした画像をビューで表示する方法について説明しています。 なお、本記事では画像のアップロードする方法については説明していません。本記事は既に実装済みの画像アップロード [...]
2020年3月4日 15:44
【Laravel】Amazon S3へのアップロードが「403 Access Denied」で失敗する原因と対処方法
# はじめに LaravelでAmazon S3へ画像アップロードする処理を実装し、いざアップロードしようとしたところ、以下のエラーが出て失敗しました。 ``` Error executing "PutObject" on "https: [...]
2020年3月4日 13:33
独自ポリシーの導入手順と注意点(ハマリポイント)を解説
# はじめに ユーザーと記事を関連付けておいて、編集や削除は記事の作成者のみ許可したいときにはポリシーを作成します。今回はポリシーの導入手順と注意点(ハマリポイント)を解説します。 # 導入手順 ## ポリシー作成 ターミナルで以下 [...]
2020年3月1日 10:32
ユーザー認証機能の導入手順と生成されたフォームを日本語化する方法を解説
# はじめに Laravelではユーザー認証機能の導入が簡単にできてしまいます。この記事ではLaravelプロジェクトにユーザー認証機能を追加する手順と、生成されたフォーム(デフォルトでは英語)を日本語化する方法を解説します。 # 前提 [...]
2020年2月29日 13:54
【Laravel 6.x】ネスト構造になっているRESTfulルーティングの定義方法
# はじめに RESTfulルーティングを定義するときは`Route::resource`を使いますが、ネスト構造になっているRESTfulルーティングの定義方法を調べたので記事にします。 # 前提 おそらく、Laravel 6.xのみ対 [...]
2020年2月28日 20:06