Use carrierwave to upload files to s3
Sometimes we need to upload files to server, we can use the “carrierwave” gem to help us. We choose the s3 as our server and we will deploy the app to heroku.
If you want to try it yourself, you can just reference the following 2 resources and skip the rest of the article.
- You can check the doc of carrierwave first for detail information.
- For uploading to s3, you can check this video from railscast.
Set AWS S3 account
You can check this video tutorial for detail process.
gem
Install “imagemagick”
$ brew install imagemagick
The reason we can’t install it by gem install command is because imagemagick is written by C, not Ruby.
If you want to use imagemagick, you had better install it before installing carrierwave and mini_magick to prevent some errors.
gem 'carrierwave'
gem 'mini_magick'
gem 'fog-aws'
The fog-aws gem will help us to upload file to s3.
Goals
This article will show you how to create a new video, which includes the small cover image and large cover image. We will upload the files to s3 via carrierwave gem.
Set tables
Create the essential columns for video
def change
create_table :videos do |t|
t.string :title
t.text :description
t.integer :category_id
t.string :small_cover # small cover of video
t.string :large_cover # large cover of video
t.string :video_url
t.timestamps
end
end
Create uploader
$ rails generate uploader large_cover
$ rails generate uploader small_cover
Edit the uploader files
app/uploaders/large_cover_uploader.rb
class LargeCoverUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagickprocess :resize_to_fill => [665, 375] # the defualt image size# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
app/uploaders/small_cover_uploader.rb
# app/uploaders/small_cover_uploader.rb
class SmallCoverUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagickprocess :resize_to_fill => [166, 236] # the defualt image size# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
Mount the uploader
Mount the uploader in video.rb
app/models/video.rb:
class Video < ActiveRecord::Base
mount_uploader :small_cover, SmallCoverUploader
mount_uploader :large_cover, LargeCoverUploader
end
Upload to s3
You can reference the code in Using Amazon S3 section.
Then we need to edit the carrierwave.rb.
app/initializers/carrierwave.rb:
CarrierWave.configure do |config|
if Rails.env.staging? || Rails.env.production?
config.fog_provider = ‘fog/aws’
config.fog_credentials = {
:provider => ‘AWS’,
:aws_access_key_id => ENV[‘AWS_ACCESS_KEY_ID’],
:aws_secret_access_key => ENV[‘AWS_SECRET_ACCESS_KEY’],
:region => ‘ap-northeast-1’ # Tokyo
} config.fog_directory = ENV[‘S3_BUCKET_NAME’]
config.storage = :fog
else
config.storage = :file
config.enable_processing = Rails.env.development?
end
end
```
Since we want to deploy our code to heroku, you need some ways to set your api key. While setting some sensitive data like api key, we need some safer way to store it, instead of hardcore the data then make it public. The better way to store the informaiton is thorugh environment variable.
You can check this page for more detail.
In this post we will set the environment variable directly on heroku.
In your console, type
$ heroku config:set AWS_ACCESS_KEY_ID=sdfafgjioas
$ heroku config:set AWS_SECRET_ACCESS_KEY_ID=sdfafgjioasjdogijaas
$ heroku config:set S3_BUCKET_NAME=your_bucket_name
Or you You can also edit config vars on your app’s settings tab on Dashboard.
Go to dashboard => your app => setting => click “Reveal Config Vars”
Then you can set the Config vars.
Check this article for more information.
Set route
resources :videos, only: [:new, :create]
Create view
The view will look like.
Basically we won’t upload video directly to s3, since it will take too much space and cost a lots. You can use service like Youtube, Vimeo or Wista.
The view template
app/controller/admin/video/new.html.haml
%section.admin_add_video
.container
.row
.col-md-10.col-md-offset-1
= bootstrap_form_for [:admin, @video], layout: :horizontal, label_col: “col-sm-3”, control_col: “col-sm-6”, html: {class: “form-horizontal”} do |f|
%ul.nav.nav-tabs
%li
%a(href=”/ui/admin_views_payments”) Recent Payments
%li.active
%a(href=””) Add a New Video
%br
%fieldset
= f.text_field :title, control_col: “col-sm-3”
= f.select :category_id, options_for_select(Category.all.map {|category| [category.name, category.id]})
= f.text_area :description, rows: 8
= f.file_field :large_cover, class: “btn btn-file”
= f.file_field :small_cover, class: “btn btn-file”
= f.text_field :video_url, label: “Video URL”
%fieldset.actions.form-group
.col-sm-6.col-md-offset-3
%input(type=”submit” value=”Add Video” class=”btn btn-default”)
Set controller
class Admin::VideosController < ApplicaitonController
def new
@video = Video.new
end
def create
@video = Video.new(video_params)
if video.save
flash[:success] = “You have created the #{video.title}”
redirect_to new_video_path
else
flash[:error] = “Please check the error, something wrong with your input.”
render :new
end
end
private
def video_params
params.require(:videos).permit!
end
end
Note: If you have the following error when uploading to s3"uninitialized constant CarrierWave::Storage::Fog”, there are some tips to solve it.
1.Create a fog.rb file under lib directory
touch lib/fog.rb
2.Add following content in the file
module Fog
# no content
end
3.Edit config/initializers/carrier_wave.rb:
require ‘carrierwave/storage/abstract’
require ‘carrierwave/storage/file’
require ‘carrierwave/storage/fog’CarrierWave.configure do |config|
# code emitted
end
```
Check evadne’s answer in this article.