There are many instances in which you may want to give the users of your application the ability to upload images--maybe you're creating a blogging platform and users want to upload images for their profiles or their posts, maybe you're creating a social networking site and users want to share pics with each other.
A few gems make file uploading and hosting very manageable in rails.
What you'll need
Once you're app is up and running, add these gems to your Gemfile:
- gem "paperclip", "~> 4.2"
- gem 'aws-sdk', '< 2.0'
Make sure you are not using the most recent version of aws-sdk. It is not compatible with Paperclip.
You will also need to have the Image Magick Library installed. In the root of your computer, run brew install imagemagick
Then, in the command line, run which convert
. This will give you the path to the Image Magick library. You need to tell Paperclip where the IM library lives. In the environments subdirectory of the config directory of your app, add the following line to production.rb and development.rb:
Paperclip.options[:command_path] = "/usr/local/bin/"
Setting up storage with AWS
If your users are going to upload images, you'll need a place to store them on the server side. If you're using a platform like Heroku, you may run in to trouble trying to store large or multiple images. Amazon Web Services makes it easy to store images in the cloud and connect that storage to your app.
- Create and AWS account and log in to the management console
- In the console, go to your 'security credentials' to get your api key and secret.
- In the console, under 'storage and services' create a new S3 bucket. A bucket is like a directory in which to store your files remotely. Give the bucket a name that relates to your app to make it easier to manage in the future as you add additional buckets for other apps.
- Lastly, attach a new security policy to your AWS user. If you haven't yet created a user in AWS:
- Click your name on the top right of the screen and select "security credentials".
- Then, on the sidebar on the left, click "Users".
- Click on the user (not the checkbox next to the user) and then click the "permissions" tab on the view you are taken to.
- Click "Attach Policy" and attach the "AdminstratorAccess" policy.
Configuring your app's environment
- Add your S3 bucket name, AWS Access key and secret access key to your application.yml (if you're using the Figaro gem) or secrets.yml file. If you're using Heroku, you will need to configure these variables with the heroku command line tools
your application.yml:
S3_BUCKET_NAME: yourbucketname
AWS_ACCESS_KEY_ID: XXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXX
in the command line:
$ heroku config:set S3_BUCKET_NAME=yourbucketname AWS_ACCESS_KEY_ID=XXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX
- Configure Paperclip with S3 in
config/production.rb
:
# config/production.rb
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV['S3_BUCKET_NAME'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
}
Adding image attachments to your model
Now, you need to create a migration to give the appropriate model the ability to have an image upload. Let's use the example of a blog post having an image uploaded to it.
rails g migration AddImageUploadToPost
Then, in your migration file:
class AddImageUploadToPost < ActiveRecord::Migration
def change
add_attachment :posts, :image_upload
end
In the Post model:
class Post < ActiveRecord::Base
has_attached_file :image_upload
validates_attachment_content_type :image_upload,
:content_type => /\Aimage\/.*\Z/
end
Uploading an image
Now, we need to give our users a form field that allows them to upload an image when they create a new post. In your form_for a new post, add the following form field:
<%= f.file_field :image_upload %>
When a user submits the form to create a new post, the parameters that you send to the create
action of the posts controller will contain the necessary info about the file. Set post.image_upload
equal to the params[:image_upload]
and save the post.
Rendering an uploaded image in the view
We're almost done! When you are ready to render an post's image in the view, simply set the image source to post.image_upload.url
. This points to the location of the image in your AWS bucket.