Ruby on Rails 이미지 업로드 with heroku, AWS S3
heroku에서 돌아가고 있는 RoR 어플리케이션의 특정 Model에 이미지를 추가하기로 했다. 그리고 선택한 방법은 AWS S3로 이미지를 저장하는 것.
gem
Gemfile에 필요한 gem을 추가한다.
# Gemfile
gem 'carrierwave', '1.2.2'
gem 'mini_magick', '4.7.0'
group :production do
gem 'fog', '1.42'
end
$ bundle install
- carrierwave: 파일 업로드 gem - https://github.com/carrierwaveuploader/carrierwave
- mini_magick: 이미지 편집 gem - https://github.com/minimagick/minimagick
- fog: cloud에 파일 업로드 gem - https://github.com/fog/fog
uploader
uploader를 생성한다.
$ rails generate uploader Picture
예시를 위해 기본적인 요소들을 생성했다.
$ rails generate scaffold Post post:text picture:string
$ rails db:migrate
Model에 uploader를 적용한다.
# app/models/post.rb
class Post < ApplicationRecord
mount_uploader :picture, PictureUploader
end
View
form field를 수정해준다. accept option을 통해 파일 validation을 적용할 수 있다.
# app/views/posts/_form.html.erb
<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
이미지 태그를 생성해준다.
# app/views/posts/index.html.erb
<%= image_tag(post.picture.url, alt: post.name) if post.picture? %>
validation
uploader validation
# app/uploaders/picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
def extension_whitelist
%w(jpg jpeg gif png)
end
end
Model validation
# app/models/teammate.rb
class Post < ApplicationRecord
validate :picture_size
private
def picture_size
if picture.size > 1.megabyte
errors.add(:picture, "1MB 이하 사진을 선택해주세요.")
end
end
end
jquery validation
# app/views/teammates/_form.html.erb
<script type="text/javascript">
$('#post_picture').bind('change', function() {
var pictureSize = this.files[0].size/1024/1024;
if (pictureSize > 1) {
alert('1MB 이하 사진을 선택해주세요.');
}
});
</script>
Imagemagick - 리사이징
Imagemagick 설치
# Ubuntu
$ sudo apt-get install imagemagick
# Mac OS
$ brew install imagemagick
Resize 설정 및 production mode에서만 cloud 업로드 설정
# app/uploaders/picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process resize_to_limit: [400, 400]
if Rails.env.production?
storage :fog
else
storage :file
end
end
AWS S3
AWS 가입, S3 bucket 생성. region은 seoul로 했다.
주의할점: butcket 이름에 “.”이 들어가면 Rails가 경로를 제대로 읽어오지 못해 에러가 난다.
carrier wave 설정
# /app/config/initializers/carrier_wave.rb
if Rails.env.production?
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => ENV['S3_ACCESS_KEY'],
:aws_secret_access_key => ENV['S3_SECRET_KEY'],
:region => 'ap-northeast-2'
}
config.fog_directory = ENV['S3_BUCKET']
end
end
- region은 본인이 사용중인 S3의 region을 기입한다.
region 찾기 - https://docs.aws.amazon.com/ko_kr/general/latest/gr/rande.html
heroku config. 보안을 위해, 파일에 직접 기입하지 않는다.
$ heroku config:set S3_ACCESS_KEY=<access key>
$ heroku config:set S3_SECRET_KEY=<secret key>
$ heroku config:set S3_BUCKET=<bucket name>
테스트용 업로드는 .gitignore
# .gitingore
/public/uploads
완료. heroku에 upload한 후 db:migrate을 해주면 끝이 난다.
$ heroku run rails db:migrate