vdeep

*

vdeepはプログラミング、IT、Web技術、ライフハックの事などなどを管理人okutaniがつぶやくブログです

【Rails】S3へ『CarrierWave+fog』を使って画像アップロードする方法

      2019/06/07

LINEで送る
Pocket


こんにちは、okutani(@okutani_t)です。本記事ではAWS(Amazon Web Services)のストレージサービスである『S3(Amazon Simple Storage Service)』へ、Ruby on Railsから『CarrierWave+fog』を使って画像をアップロードするまでを紹介しています。

『CarrierWave』は単純に画像アップロードをおこなうために利用し、fogを使うことでクラウド上にあるS3へのアップロードを簡易的におこなえるようにしています。

S3を利用できる状態にしておく必要があるため、以下の公式サイトから利用登録しておきましょう。ちなみに、新規登録から1年間は無料で利用できます。

LINKAmazon S3 (スケーラブルなクラウドストレージサービス ) | AWS

また、CarierWaveに似た「Paperclip」というgemを使っても同じような実装をおこなうことができます。今回は解説しませんが、CarrierWaveとPaperclipの違いについては以下のサイトを参考にしてください。

参考Paperclip と CarrierWave を結構マジメに比較してみた – 彼女からは、おいちゃんと呼ばれています

S3の料金体制については以下の記事が分かりやすいです。参考にしてください。

参考S3の料金体系が分かりにくいと聞かれたので纏めた – Qiita

今回、Railsのバージョンは5.0.1、Rubyバージョン2.3.0を使って作業を進めています。

それでは、S3サーバーにで画像をアップロードする方法をみていきましょう。

スポンサーリンク

S3の初期設定

まずはじめに、S3の初期設定をおこないます。

IAMグループ、IAMユーザーの作成

IAM(AWS Identity and Access Management)を利用することで、ユーザーごとにアクセス制御をおこなうIAMユーザーを作成することができます。

IAMはLinuxでいうところの「rootとuser」の関係のようなものなので、必ずはじめに作成するようにしましょう。

以下の公式サイトTOPから「アカウント」→「セキュリティ認証情報」を選択し、ログインします。

LINKアマゾン ウェブ サービス【AWS 公式】 - クラウドコンピューティングサービス

IAMマネジメントコンソールにログインしたら、S3のみ利用できるグループを先に作成しておきます。

以下の流れはIAMの管理のしかたによってかなり変わってくるかと思うので、一例として読み進めてください。

グループの作成

「グループ」→「新しいグループの作成」をクリック。

グループ名を入力。今回はS3usersにしてみました。

次のステップへ進み、ポリシーを決めていきます。s3で絞りこみをして「AmazonS3FullAccess」を選択。

ポリシーは細かく設定することもできますが、今回は分かりやすくS3をフルに使えるグループを作成してみました。

ユーザーの作成

次にユーザーを作成します。

「ユーザー」→「ユーザーを追加」を選択。

ユーザー名を入力。今回はs3userとしましたが、ご自身のプロジェクトに合わせて作成してみてください。

すぐ下の「AWS アクセスの種類を選択」を設定します。今回は次のとおり設定してみました。

  • プログラムによるアクセス: ON
  • AWS マネジメントコンソールへのアクセス: ON
  • AWS マネジメントコンソールへのアクセス: ON
  • AWS マネジメントコンソールへのアクセス: ON
  • コンソールのパスワード: 自動生成パスワード(どちらでも可)
  • パスワードのリセットが必要: ON

もし、マネジメントコンソールへのアクセス許可をしない場合は、該当箇所のチェックをOFFにしてください。

次のステップに進み、先ほど作成した「S3users」グループを選択します。

「ユーザーの作成」を選択してユーザを作成します。

ユーザーが作成できました。

「.csvのダウンロード」をクリックして、ユーザー情報を取得しておきましょう。「credentials.csv」ファイルがダウンロードされます。

取得したユーザー情報は外部に漏れないよう保管しておく必要があるので注意してください。

作成したユーザーでログイン

それでは、s3userのアカウントでAWSマネジメントコンソールへログインしてみます。

先ほどダウンロードしたCSVファイルに、ログイン情報とs3user専用のURLが記載されています。

通常のマネジメントコンソールへのログインURLとは別のURLになるので注意しましょう。

サインインすると、パスワードを変更するように促されるので変更します。

AWSマネージメントコンソールにログインできました。S3以外のサービスをクリックすると、権限がないことが確認できます。

それでは、作成したユーザーを使って、画像アップロード場所である「バケット」を作成していきます。

バケットの作成

S3からバケットを作成していきます。s3userのまま操作していきましょう。

「サービス」→「S3」を選択。

「バケット」の作成をクリック。

「バケット名→好きな名前」「リージョン→Tokyo」を選択、「作成」をクリック。

ちなみに、バケット名はURLにも利用されるので、「proj-image-store」のように『ハイフン区切りかつユニークな英数字列』にしてくと良いですね。

バケットの名前の付け方は以下のサイトが参考になります。

参考code.rock: S3のバケット名はよく考えて命名しましょう!

リージョンは日本のサービスなら、一番近い「Tokyo」を選択しましょう。それ以外の場所であれば、適宜選択してください。

もし、画像をやりとりしたログ記録を取りたい場合は「ログ記録のセットアップ」からおこないます。今回はログ記録の説明は省略して進めます。

これでバケットが作成されました!

ImageMagickの導入

画像操作をおこなうので、ImageMagickというツールを先に導入しておきます。ImageMagickは画像操作をおこなうときに広く使われているツールですね。

今回は確認用としてMacに導入します。Homebrewを使うとかんたんに導入できます。

……なのですが、私の環境では最新版だと実行時にコケてしまったので、最新版の7.0.4-9ではなく、6-6.9.7-8を導入しました。

$ brew tap homebrew/versions
$ brew install imagemagick@6

もし、Homebrew自体がよくわからない方は、「MacにHomebrewを導入する方法&使い方まとめ | vdeep」を参考にしてください。

yumが使えるLinux(CentOSなど)であれば、以下のコマンドで導入できます。

$ yum install imagemagick

ただし、今回はLinux上での動作チェックはおこなっていませんのであしからず。

では、CarrierWaveを導入して、Ruby on RailsでS3に画像をアップロードするまでをみていきましょう。

CarrierWaveの導入

GemfileにCarrierWaveを記述していきます。以下をRailsアプリ以下にあるGemfileに追記。

[追記:2019/6/7]執筆当時はRMagickを利用していましたが、CarrierWave公式がMiniMagickをおすすめしていたのでMiniMagickを利用するようにリライトしました

gem 'carrierwave'
gem 'fog-aws'
gem 'mini_magick'

CarrierWave以外のgemも導入していますが、「fog-aws」はS3へのアップロードを簡易的におこなうため、「mini_magick」はImageMagickを操作してサムネイル画像などを作成するために必要です。

ただ単に、サーバー上へ画像をアップするだけであれば、CarrierWaveのみでもOKです。

今回はS3へのアップロード、画像切り出し操作などもおこないたいため、それぞれのgemを導入しています。

今回は、以下のコマンドでRailsプロジェクト配下にgemをインストールします。

$ bundle install --path vendor/bundle

これでbundle installが通り、CarrierWave, fog-aws, mini_magickの導入が完了しました。

Uploaderの作成

それでは、Rails側の設定をおこなっていきましょう。

まずはCarrierWaveで利用するUploaderを作成します。rails generateコマンドでさくっと作成できます。

$ rails g uploader Image

「app/uploaders/image_uploader.rb」が生成されます。

今回は、以下のようにimage_uploader.rbを書き換えてみました。

class ImageUploader < CarrierWave::Uploader::Base

  include CarrierWave::MiniMagick

  storage :fog

  # S3のディレクトリ名
  def store_dir
    "sample-image/#{model.id}"
  end

  # デフォルト画像は1200x5000に収まるようリサイズ
  process resize_to_limit: [1200, 5000]

  # サムネイル画像
  version :thumb do
    process resize_to_fill: [100, 100]
  end

  # 許可する画像の拡張子
  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  # 保存するファイルの命名規則
  def filename
     "#{secure_token(10)}.#{file.extension}" if original_filename.present?
  end

  # 一意となるトークンを作成
  protected
  def secure_token(length=16)
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.hex(length/2))
  end
end

上記は一例です。お好きな設定に変えて使ってみてください。

もっといろいろとお好みにリサイズしたい場合は、以下のサイトが分かりやすくまとまっているので参考にしてください。

参考CarrierWave + RMagick 画像のリサイズをまとめてみました - 麺処 まつば

ModelにUploaderを紐付ける

作成したUploaderをModelに紐付けます。今回は、Userモデルに紐付けると仮定して進めます。

class User < ApplicationRecord
  mount_uploader :image, ImageUploader
end

「:image」の部分は適宜利用したいモデルのカラム名に変更してください。

モデルの作り方や、CRUDなどの実装などがよく分かっていない方は、Rails入門書籍などを参考にしてみてください。今回は話をかんたんにするため、モデルやコントローラの作成方法については割愛しています。

viewの実装

画像アップロードのviewを作成します。

<%= form_for(@user) do |f| %>
  <%= f.file_field :name %>
  <%= f.file_field :description %>

  <% if @user.persisted? && @user.image? %>
    <%= image_tag @user.image.thumb.url %>
    <label><%= f.check_box :remove_image %> 画像を削除</label>
  <% else %>
    <%= f.file_field :image %>
    <%= f.hidden_field :image_cache %>
  <% end %>
<% end %>

上記は一例です。利用するモデルに応じて作成してみてください。

上記の例では、画像がすでにアップされていれば「サムネイル画像+画像を削除ラベル」を表示して、画像削除もできるようにしています。

また、「:image_cache」を利用すると、バリデーション時に画像が消えずにキャッシュしたものを表示してくれます。その場合、Controller側のpermitにimage_cacheを追加しておく必要があります。のちほど設定します。

ただ、私の環境だとバリデーション後にキャッシュはされているものの、キャッシュされていることが画面上で確認することができませんでした。もし解決できたら追記します。

carrierwave.rbの作成

「config/initializers/carrierwave.rb」を以下の内容で作成します。

CarrierWave.configure do |config|
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider:              'AWS',
    # アクセスキー
    aws_access_key_id:     'ここにアクセスキー',
    # シークレットキー
    aws_secret_access_key: 'ここにシークレットキー',
    # Tokyo
    region:                'ap-northeast-1',
  }

  # 公開・非公開の切り替え
  config.fog_public     = true
  # キャッシュの保存期間
  config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" }

  # キャッシュをS3に保存
  # config.cache_storage = :fog

  # 環境ごとにS3のバケットを指定
  case Rails.env
    when 'production'
      config.fog_directory = 'プロジェクト名-image-store'
      config.asset_host = 'https://プロジェクト名-image-store.s3-ap-northeast-1.amazonaws.com'

    when 'development'
      config.fog_directory = 'dev-プロジェクト名-image-store'
      config.asset_host = 'https://dev-プロジェクト名-image-store.s3-ap-northeast-1.amazonaws.com'

    when 'test'
      config.fog_directory = 'dev-プロジェクト名-image-store'
      config.asset_host = 'https://dev-プロジェクト名-image-store.s3-ap-northeast-1.amazonaws.com'
  end
end

# 日本語ファイル名の設定
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/

上記の項目は好きに変更して使ってください。

リージョンの設定項目については以下を参考に。Tokyoであれば「ap-northeast-1」を指定すればOKです。

参考AWS のリージョンとエンドポイント - アマゾン ウェブ サービス

環境ごとにS3のバケットを切り替えることもできますし、キャッシュファイルをS3に持つこともできます。便利ですね。

dev用にバケットを分ける場合は新しくバケットを追加してください。私は「dev-プロジェクト名-image-store」の形式で新しく作成してみました。

日本語化(I18n)設定

日本語化対応をおこなうには、以下のファイルを「config/locales/carrierwave_ja.yml」に設置します。

carrierwave-i18n/ja.yml at master · carrierwaveuploader/carrierwave-i18n

ja:
  errors:
    messages:
      carrierwave_processing_error: 処理できませんでした
      carrierwave_integrity_error: は許可されていないファイルタイプです
      carrierwave_download_error: はダウンロードできません
      extension_whitelist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできるファイルタイプ: %{allowed_types}"
      extension_blacklist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできないファイルタイプ: %{prohibited_types}"
      content_type_whitelist_error: "%{content_type}ファイルのアップロードは許可されていません。アップロードできるファイルタイプ: %{allowed_types}"
      content_type_blacklist_error: "%{content_type}ファイルのアップロードは許可されていません"
      rmagick_processing_error: "rmagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}"
      mini_magick_processing_error: "MiniMagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}"
      min_size_error: "を%{min_size}以上のサイズにしてください"
      max_size_error: "を%{max_size}以下のサイズにしてください"

設置後はRailsサーバーを再起動してください。

アップロードの動作確認

適宜、UsersControllerを作成して、普段どうりCRUDで実装します。以下createの例です。

def create
  @user = User.new(user_params)
  if @user.save
    redirect_to users_path, notice: 'ユーザーが新規追加されました!'
  else
    render :new
  end
end

その際、Strong Parametersに画像関連のパラメータを追加しておきましょう。

private

def user_params
  params[:user].permit(
    :name,
    :description,
    :image,
    :image_cache,
    :remove_image
  )
end

アップロードを実行すると、usersテーブルのimageカラムにはUploaderのオブジェクトが、S3には画像ファイルがアップロードされているのが確認できるかと思います。

publicで投稿していれば、プロパティからURLを取得することで、直接画像にアクセスすることができます。

これでRuby on Railsで画像管理をS3でおこなうことができますね!

まとめ

本記事ではS3へのアップロードをRuby on Railsからおこなうため、CarrierWave+fogを使って実装を進めました。

はじめてS3を利用する場合、グループやユーザーの作り方がちょっと特殊で戸惑うかと思いますが、AWS関連の勉強にもなるのでじっくり取り組みましょう。

S3ではバックアップもしっかりおこなってくれますし、格安で大量のファイルを管理することができるので、本記事を参考にして理想のストレージ環境を作ってみてください。

Ruby on Railsユーザーの参考になれば幸いです。

LINEで送る
Pocket

okutani (okutani_t) のヒトコト
S3の設定からCarrierWave, fog, MiniMagickもろもろを導入するだけで大変ですね。。でもこれで便利に画像アップロードできるようになりました。

Web開発のお仕事を募集しています

フリーランスのエンジニアとして、Webシステム開発のお仕事依頼を随時募集しています(現在の業務量によってお受けできない場合もあります)。

Ruby on Rails」「JavaScript(jQuery, Reactなど)」「HTML + CSS」を用いたシステム開発、「Heroku」等を用いたサーバー構築・運用、「Git」や「GitHub」を利用したソーシャルコーディングなどに対応しています。

ご依頼を検討している方は、下記リンク本ブログからのお問い合わせ、もしくはokutaniのポートフォリオからご連絡ください。

LINKお問い合わせ

LINKokutani's Portfolio


 - Ruby on Rails

スポンサーリンク

PC用AdSense

PC用AdSense

  こちらもどうぞ

vdeepのトップページへ戻る画像です。風船の形をした島を女の子が掴んでいます。