Railsでpaperclipを使ってリサイズしつつS3へ画像をアップロードする
RubyonRailsアプリで、画像アップロード機能を作るにあたって、paperclipを試すことにしたので、技忘録。
想定するユースケース
- エンドユーザ向け画面/管理画面で画像アップロード機能を作りたい
- アップロードした画像はいくつかのサイズにリサイズして使うことを想定する
- 画像はWebサーバ内部ではなく、オンラインストレージを使用して保存する
- アップした画像はWebアプリから参照したい
- アップロードはWebアプリからのみ許可したい
- なるべくシンプルに作りたい
構成
- Ruby 2.1.4
- Rails 4.1.7
- Imagemagick 6.8
- Paperclip 4.2
これらをOSX Yosemite上で実行し、オンラインストレージにはAmazon S3を使います。
前提
事前準備
- ImageMagickのインストール
画像のリサイズにはimagemagickを使うのでbrewでインストール
$ brew install imagemagick
:warning: CentOSとかならyumでインストールしてください
- Gem追加
paperclipとaws-sdk, rmagickのGemを追加して
gem 'paperclip' gem 'aws-sdk' gem 'rmagick'
bundle install
します
$ bundle install
Gemfile.lockが更新されます。
Model
- Modelに画像保存用の設定を追加する
class Hoge < ActiveRecord::Base has_attached_file :image, :styles => { :thumb => "90x60", :medium => "180x120", :large => "600x400" }, :storage => :s3, :s3_permissions => :private, :s3_credentials => "#{Rails.root}/config/s3.yml", :path => ":attachment/:id/:style.:extension" validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png"] def authenticated_image_url(style) image.s3_object(style).url_for(:read, :secure => true) end end
- Migrationを作る
$ rails g migration AddAttachmentImageToHoges
- migrationファイルの中身はこんな感じ
class AddAttachmentImageToHoges < ActiveRecord::Migration def change change_table :hoges do |t| t.has_attached_file :image end drop_attached_file :hoges, :image end end
- Migrate
$ rake db:migrate
これで
- image_file_name
- image_content_type
- image_file_size
- image_updated_at
の4つのカラムがDBに追加されます。
Controller, View
次にControllerとViewを作っていきます。
$ rails g controller hoges index show new edit
Controller
class HogesController < ApplicationController before_action :set_hoge, only: [:show, :edit] def index @hoges = Hoge.all end def new @hoge = Hoge.new end def show end def edit end # とりあえず、createだけ追加 def create @hoge = Hoge.new(hoge_params) respond_to do |format| if @hoge.save format.html { redirect_to @hoge, notice: 'Hoge was successfully created.' } format.json { render action: 'show', status: :created, location: @hoge } else format.html { render action: 'new' } format.json { render json: @hoge.errors, status: :unprocessable_entity } end end end private def set_hoge @hoge = Hoge.find(params[:id]) end def hoge_params params.require(:hoge).permit(:name, :image) end end
View
- 新規登録画面
<div class="field"> <%= f.label :name %> <%= f.text_field :name %><br> <%= f.label :image %> <%= f.file_field :image %> </div> <div class="actions"> <%= f.submit %> </div>
- 一覧画面
<% @hoges.each do |hoge| %> <tr> <td><%= hoge.id %></td> <td><%= image_tag(hoge.authenticated_image_url(:thumb)) if hoge.image.present? %></td> <td><%= link_to 'show', hoge %></td> <td><%= link_to 'edit', edit_hoge_path(hoge) %></td> <td><%= link_to 'destroy', hoge, method: :delete, data: { confirm: 'are you sure?' } %></td> </tr> <% end %>
- 部分テンプレート
<%= @hoge.name %> <%= image_tag(@hoge.authenticated_image_url(:large)) if @hoge.image.present? %>
Routes
hogesへのrouteを追加します。
resources :hoges
S3
Bucketを作る
AWSのManagementConsole上でS3のBucketを作ります。
接続情報
config/s3.yml
として、S3への接続情報を記述します
bucket: 'bucket_name' access_key_id: '12345678' secret_access_key: '12345678901234567890' s3_host_name: 's3-ap-northeast-1.amazonaws.com' # tokyoリージョンの場合
これで準備は完了です。
実行
Railsアプリを動かして /hoges/ へアクセスして、"new hoge"リンクを押下して画像データを追加します。
CreateしたらAWSのコンソール上でS3のBucketの中身を確認します。
所感
- paperclip便利
- めちゃ便利です
- S3、ImageMagickとの連携が非常に手軽に行えます
- 静的コンテンツをWebサーバに置かなくていいのはラク
- 静的コンテンツをWebサーバ内に置かなくていいのは非常に良いですね
- S3ならそのままCloudFrontでCDN対応もできます
- Webサーバをスケールアウトしても静的コンテンツはそのままで良いし、運用もラクです
- 画像ファイルのURL生成をRails側で処理することについては...
- 一方、画像URL生成をRailsで処理させることになるので、ここはフラグメントキャッシュを使って、キャッシュした方が良い部分かもしれません
- CarrierWave
- 対抗馬と目される、Carrierwaveも試してみようと思います