If you are building a web application, you definitely will want to enable image uploading. Image uploading is an important feature in modern-day applications, and images have been known to be useful in search engine optimization.
In this tutorial (which is the first part of the Rails Image Uploading series), I will show you how to enable image uploading in your Rails application using CarrierWave. It will be a simple application as the focus is on the image uploading.
CarrierWave is a Ruby gem that provides a simple and extremely flexible way to upload files from Ruby applications. You need to have Rails on your machine to follow along. To be sure, open up your terminal and enter the command below:
rails -v
That will show you the version of Rails you have installed. For this tutorial I will be using version 4.2.4, which you can install like so:
gem install rails -v 4.2.4
With that done, you are good to go.
Rails Application Setup
Now create a new Rails project:
rails new mypets
Open up your Gemfile and add the following gems.
*Gemfile*
...
gem 'carrierwave', '~> 0.10.0'
gem 'mini_magick', '~> 4.3'
...
The first gem is for CarrierWave, and the second gem called mini_magick helps with the resizing of images in your Rails application. With that done, run bundle install.
Generate a scaffold resource to add CarrierWave’s functionality. Run the following command from your terminal:
rails g scaffold Pet name:string description:text image:string
A scaffold in Rails is a full set of model, database migration for that model, controller to manipulate it, views to view and manipulate the data, and a test suite for each of the above.
Migrate your database next:
rake db:migrate
Setting Up CarrierWave
You need to create an initializer for CarrierWave, which will be used for loading CarrierWave after loading ActiveRecord.
Navigate to config > initializers and create a file: carrier_wave.rb.
Paste the code below into it.
*config/initializers/carrier_wave.rb*
require 'carrierwave/orm/activerecord'
From your terminal, generate an uploader:
rails generate uploader Image
This will create a new directory called uploaders in the app folder and a file inside called image_uploader.rb
. The content of the file should look like this:
*app/uploaders/image_uploader.rb*
# encoding: utf-8
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# 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
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process :resize_to_fit => [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_white_list
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
You can edit it to fit what you want. Let me take you through it.
First, uncomment the MiniMagick line. That should be line 7.
...
include CarrierWave::MiniMagick
...
You need this to generate different versions of an image. If you want to generate a thumbnail version of images uploaded, there is already a code form included in the image_uploader file for you. Uncomment the version code block as shown below:
...
version :thumb do
process :resize_to_fill => [50, 50]
end
...
You can also add different versions using the same format.
For the purpose of this tutorial, we will be saving to file and not fog. Fog is the Ruby cloud service library. I will show you how to put it into use in another part of this series. So leave your storage option as it is.
For security purposes, certain files might pose a threat if allowed to be uploaded to the wrong location. CarrierWave allows you to specify a white-list of allowed extensions. You should see a method that looks like what I have below, so uncomment it.
...
def extension_white_list
%w(jpg jpeg gif png)
end
...
It is time to mount your uploader. Navigate to your model and paste the code below.
*app/model/pet.rb*
mount_uploader :image, ImageUploader
Go to your views and edit it to look like what I have below:
app/views/pets/_form.html.erb
<%= form_for @pet, html: { multipart: true } do |f| %>
<% if @pet.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@pet.errors.count, "error") %> prohibited this pet from being saved:</h2>
<ul>
<% @pet.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :image %><br>
<%= f.file_field :image %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Open your terminal and start your rails server: rails s
.
Point your browser to http://localhost:3000/pets. You should be able to add a new pet by entering a name and description and uploading an image. The image does not get displayed after successful upload. Let me show you how to fix that.
Navigate to your show page where you are displaying the image, and edit it to fit what I have below:
*app/views/pets/show.html.erb*
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= @pet.name %>
</p>
<p>
<strong>Description:</strong>
<%= @pet.description %>
</p>
<p>
<strong>Image:</strong>
<%= image_tag @pet.image.thumb.url %>
</p>
<%= link_to 'Edit', edit_pet_path(@pet) %> |
<%= link_to 'Back', pets_path %>
This will display the thumbnail version of the image.
CarrierWave makes it easy to remove a previously uploaded file on a mounted uploader with just a checkbox. I will show you how to do it.
Open up your form file and make a little adjustment. Edit it to look like this:
*app/views/pets/_form.html.erb*
<%= form_for @pet, html: { multipart: true } do |f| %>
<% if @pet.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@pet.errors.count, "error") %> prohibited this pet from being saved:</h2>
<ul>
<% @pet.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :image %><br>
<%= f.file_field :image %>
<% if f.object.image? %>
<%= image_tag f.object.image.thumb.url %>
<%= f.label :remove_image %>
<%= f.check_box :remove_image %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In the code above, we checked if there is already an image object. If there is, we display the image and the option to remove it, but if there is none, we display just the field to upload the image.
Navigate to your controller and add :remove_image
to your params. Reload your edit page, tick the box, click on Update Pet, and the image will be removed.
Validating Image Size
There are different means of doing this. I will show you an easy and quick method. Open up your pet model and paste in the code below:
*app/model/pet.rb
validates_processing_of :image
validate :image_size_validation
private
def image_size_validation
errors[:image] << "should be less than 500KB" if image.size > 0.5.megabytes
end
This will help ensure that no image greater than 500KB gets uploaded to your Rails application. Start your rails server and check out what you have.
Conclusion
Now you know how to enable image uploading in your Rails application. You have also learned how to validate the format and size, as well as deleting an image. In the next part of this series, we will look at how to use CarrierWave alongside Devise.
by Kingsley Silas Chijioke via Envato Tuts+ Code