いくつか方法はあるみたいなんですが、s3バケット内にディレクトリも作らせたかったので、今回はPaperclipを使うことにしました。
userモデルはすでにあって、そこにプロフ画像を追加します。
環境
Rails4.0.0
Ruby2.0.0-p246
参考URL
RailsでPaperclipを使ってAmazon S3に画像を保存する
http://www.aguuu.com/archives/2012/12/paperclip/
公式
paperclip
https://github.com/thoughtbot/paperclip
下準備
S3にアクセスするユーザを作成する
その際に、Access Key IDとSecret Access Keyをメモしておく
S3にバケットを作成
image-upload
とか本番・開発で分けたかったら分けて立てる
先ほど作成したユーザにpermissionタブから割り当てるのを忘れずに。(権限は、show/edit permissionは外していいと思う)
Gemfileに登録
gem 'paperclip'
gem 'aws-sdk'
bundle install
ここから本番
DBに画像保存用のカラムを追加
DBに保存と言っても、画像そのものじゃなくて画像ファイル名とかコンテントタイプとかの保存に使うようです。
rails generate paperclip user avatar
create db/migrate/20140424060535_add_attachment_avatar_to_users.rb
migrationファイルの中はこんな感じ。
class AddAttachmentAvatarToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
t.attachment :avatar
end
end
def self.down
drop_attached_file :users, :avatar
end
end
migrateする
rake db:migrate
S3の設定ファイルを作成する
東京リージョンにs3を立てた場合は、host_nameはs3-ap-northeast-1.amazonaws.com固定っぽい。
bucket: image-upload
access_key_id: IAMで作成したユーザのkey_id
secret_access_key: IAMで作成したユーザのaccess_key
s3_host_name: s3-ap-northeast-1.amazonaws.com
本番環境とstg環境でバケットを分けたい場合は、環境毎に書けるみたい。
userモデルにアタッチするファイルの情報を記述する
以下を記述すればOK。pathはここでは更新時間をファイル名にしているけど、ハッシュ値とか他にも使えるよう。
has_attached_file :avatar,:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:url => "s3_domain_url",
:path => ":attachment/:id/:updated_at.:extension"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
current_user.avatar = user_params
def user_params
params.require(:user).permit(:avatar)
end
これだけでs3へ保存が出来ました!簡単!
ドハマりポイント
保存自体はすぐに出来たんだけど、s3に置いたファイルのURLが取れなくて右往左往してました。。。
DBに保存してあるファイル名とURLが別ってちょっと詐欺チックだと思う。
ちなみに、DBに保存されるファイル名は、元ファイルのファイル名。
# avatar.path はpathで設定した内容が返ってくる→相対パス
avatar.path
=>/avatar/1111/123456789.png
# avatar.path は実際にs3に置いたパスが返ってくる→絶対パス
avatar.url
=>http://s3-ap-northeast-1.amazonaws.com/hogehoge/avatars/1111/123456789.png?123456789
んで、urlを取れるようになったはいいけど、クエリに更新時間(ファイル名)がついてる。。なんでやー。
クエリなしにしたかったけど、よくわからなかったので、クエリ部分をsplitして端末に返すという荒業をしましたw
画像のキャッシュ対策なんだろうか。。
にしても、urlってどこで持ってるんだろう。。メモリかな?
未だになれないRailsのよろしく感。