Edited at

ParperClipで画像投稿までの過程をまとめたよ(AWS cloud9 + Heroku + S3)

More than 1 year has passed since last update.


はじめに

Ruby on Railsで画像を投稿する機能を作っている友人が、途中でハマっていたので、自分でも最小限の機能を実装してみました。

途中の過程で色々な記事を往復しましたので、条件が同じ人に活用して貰いたく、ここにまとめます。

実装は、以下の流れで試しました。


  1. local(cloud9)で画像の投稿

  2. cloud9から画像の保存を S3に行う

  3. Herokuにデプロイして、S3に画像の保存を行う

今回の記事では以下の内容は、詳しくは説明しません。

S3でのバケットの作成

Herokuアカウントの登録


対象となる読者

Rails初学者、半年以内で、自ら小さなプロダクトを作ってみようと考えている方。


操作を行った環境

ruby 2.3.1p112

rails 5.0.6


詳細


1.AWScloud9にImageMagickを導入する

公式にもあるように ImageMagickが動作させる環境に入っていないと、PaperClipは使えないとのこと。まずは ImageMagickを cloud9に導入します。

旧cloud9の記事から流れとしては、 apt-get update を行って sudo apt-get install imagemagick とのことで、この内容に従って進めます。

$ sudo apt-get update                                                                                              

sudo: apt-get: command not found

apt-get というコマンドが見つからないとお叱りを受ける。

親切なことに、cloud9でこのようにアラートメッセージが出力されました。

どうやら、Amazon Linuxを使用している場合は、RedHatベースのCentOSベースのため、 apt-get ではなく yum を使用するようです。

$ sudo yum update 

~(中略)
Complete!

いけたようなので続いて sudo yum install imagemagick を実行します。

$ sudo yum install imagemagick

Loaded plugins: priorities, update-motd, upgrade-helper
1054 packages excluded due to repository priority protections
No package imagemagick available.
* Maybe you meant: ImageMagick
Error: Nothing to do

有効な imagemagick というパッケージはないと怒られる。エラーのヒントの通り実行します。

$ sudo yum install ImageMagick

Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main
~(中略)
Complete!

成功したようなので、 convert --version で確認するImageMagickが入っているか確認します。

$ convert --version

Version: ImageMagick 6.7.8-9 2016-06-22 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP

無事に、ImageMagickの導入は完了しました。


2. アプリケーションにpaperclipを導入する

STEP1:ローカルで画像投稿が出来るか確認

※最小限のアプリケーションに今回は画像投稿、表示の機能を付け加えていく。 Message というモデルにカラムを追加し、画像を投稿できるように実装する。


Gemfile

gem "paperclip", "~> 6.0.0"


上記をGemfileに記述し bundle install を行います。


3. Migration, Model, Controller, Viewを準備する

Messageモデルに新しく投稿する画像を imageカラム を追加します。migrationファイルの作成を以下のコマンドで実行します。

rails g migration AddAttachmentImageToMessages

新しく追加されたmigrationファイルを以下のように変更します。

class AddAttachmentImageToMessages < ActiveRecord::Migration[5.0]

def self.up
change_table :messages do |t|
t.attachment :image
end
end

def self.down
remove_attachment :messages, :image
end
end

rails db:migrate で変更を schema.rb に反映させます。反映された schema.rb には以下の4つのカラムが追加されています。

  create_table "messages", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|

~(中略)
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
end

続いてMessageモデルの中身に以下を追加します。


message.rb

class Message < ApplicationRecord

~(中略)
has_attached_file :image,
:styles => { medium: "300x300>", thumb: "100x100>" },
:default_url => "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
end

Contollerを変更


messages_controller.rb

def create

@message = Message.create(message_params)
end

def message_params
params.require(:message).permit(:image)
end


必要な記述を対象のViewページに付け加えます。

rails s -b $IP -p $PORT でサーバーを起動して、画像を投稿してみると、、、

ローカルでの画像投稿完成!

投稿された画像はどこに保存されるかというと、 application名/public/system/ というディレクトリが新しく作成されており、その中に保存されています。


4. アプリケーションにaws-sdk-s3を導入する。

STEP2:ローカルからS3に画像を保存する

ParperClipの公式ページに以下のように記述があります。

You may also choose to store your files using Amazon's S3 service. To do so, include the aws-sdk-s3 gem in your Gemfile:


Gemfile

gem 'aws-sdk-s3'


bundle install を行います。


Gemfile

gem 'aws-sdk-s3'


bundle install 後にこのようなNoteが表示されました。

##################################################

# NOTE FOR UPGRADING FROM 4.3.0 OR EARLIER #
##################################################

Paperclip is now compatible with aws-sdk >= 2.0.0.

If you are using S3 storage, aws-sdk >= 2.0.0 requires you to make a few small
changes:

* You must set the `s3_region`
* If you are explicitly setting permissions anywhere, such as in an initializer,
note that the format of the permissions changed from using an underscore to
using a hyphen. For example, `:public_read` needs to be changed to
`public-read`.

For a walkthrough of upgrading from 4 to 5 and aws-sdk >= 2.0 you can watch
http://rubythursday.com/episodes/ruby-snack-27-upgrade-paperclip-and-aws-sdk-in-prep-for-rails-5

Paperclipは aws-sdk >= 2.0.0. と互換性があり、 S3 storageを使うなら、 aws-sdk >= 2.0.0s3_region の設定が必要不可欠で、アクセス許可の形式で - を使っている箇所は _ に書き換えないといけないとのこと。

Paperclip with Amazon S3 によると

storage, s3_host_name, :bucket を設定するとのこと。加えて access_key_id, secret_access_key を追記します。


development.rb

  config.paperclip_defaults = {

:storage => :s3,
:s3_host_name => 's3-ap-southeast-1.amazonaws.com',
:bucket => ENV['S3_BUCKET_NAME'],
:s3_credentials => {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
}
}

大事な内容は .bash_profile に環境変数に設定してそこから参照するようにします。

echo export S3_BUCKET_NAME="S3のBucket Name" >> ~/.bash_profile

echo export AWS_ACCESS_KEY_ID="AWSのaccess_key_id" >> ~/.bash_profile
echo export AWS_SECRET_ACCESS_KEY="AWSのsecret_access_key" >> ~/.bash_profile

#書き込んだ .bash_profileの内容を読み込む
source ~/.bash_profile

サーバーを立ち上げ、画像を投稿するとエラーが発生しました。

undefined method match for nil:NilClass Did you mean? catch

調べると、これは S3のregionの設定がされていないことが原因。そういえば、 aws-sdk-s3 を導入したときに Noteで You must set the s3_region と書いてあったのを忘れていたので、記述します。


development.rb

  config.paperclip_defaults = {

:storage => :s3,
:s3_host_name => 's3-ap-southeast-1.amazonaws.com',
:bucket => ENV['S3_BUCKET_NAME'],
:s3_region => ENV['AWS_REGION'], #追記
:s3_credentials => {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
}
}

再度 .bash_profile に環境変数に設定してそこから参照するようにします。

echo export AWS_REGION="S3のRegion" >> ~/.bash_profile

#書き込んだ .bash_profileの内容を読み込みます。
source ~/.bash_profile

※Regionがよくわからない場合はこちらの公式ページを参照。

実際に投稿してみる。

無事に投稿完了!!


5. Herokuにアプリをupしてから画像をS3に保存

STEP3:HerokuからS3に画像を保存する

まずは、production環境に以下の記述を追記します。


production.rb

  config.paperclip_defaults = {

:storage => :s3,
:s3_host_name => 's3-ap-southeast-1.amazonaws.com',
:bucket => ENV['S3_BUCKET_NAME'],
:s3_region => ENV['AWS_REGION'],
:s3_credentials => {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
}
}

続いてCloud9に Heroku CLIが導入されていない場合は、CLIを導入していきます。

wget https://cli-assets.heroku.com/heroku-cli/channels/stable/heroku-cli-linux-x64.tar.gz -O heroku.tar.gz

sudo mkdir -p /usr/local/lib/heroku

sudo tar --strip-components 1 -zxvf heroku.tar.gz -C /usr/local/lib/heroku

sudo ln -s /usr/local/lib/heroku/bin/heroku /usr/local/bin/heroku

ターミナルから Heroku にログインしましょう。Herokuに登録してある mailとpasswordをターミナルから打ち込みます。

heroku login

Enter your Heroku credentials.
Email: Herokuに登録したメールアドレスを入力
Password: Herokuに登録したパスワードを入力

ログインに成功した場合は Logged in as 登録したmailアドレス が表示されます。

続いて、 Heroku にアプリケーションを作成しましょう。

heroku create 作成するHerokuアプリケーション名

※アプリケーション名は Heroku上で一意 である必要があるため、他の人と重複したアプリケーション名は命名出来ません。

念のためアプリケーションが作成されたかを確認します。

heroku apps

Herokuの DBPostgreSQL のため、 mysqlなど他の DBを使っている場合は以下の追加が必要です。


Gemfile

group :production do

gem 'pg', '0.21.0'
end

Development環境でbundle installする必要はないので以下のコマンドで bundle install します。

bundle install --without production

今までの変更を、忘れずに commit しておきましょう。

ここまで出来たら、デプロイ作業に入ります。以下のコマンドでデプロイ。

git push heroku master

続いて heroku run コマンドでマイグレーションを実行していく。

heroku run rails db:migrate

それでは、 Herokuアプリ で画像を投稿してみます。

無事成功!? かと思いきや、S3を確認すると、対象の画像は保存されていません。

これは、HerokuにAWSの設定を追加してないからです。

公式に従って、必要な設定を登録していきます。

heroku config:set S3_BUCKET_NAME=your_bucket_name

heroku config:set AWS_ACCESS_KEY_ID=your_access_key_id
heroku config:set AWS_SECRET_ACCESS_KEY=your_secret_access_key
heroku config:set AWS_REGION=your_aws_region

再度 Herokuアプリを開き画像を投稿!

無事S3の中に対象の画像が保存されました!