Skip to main content Link Search Menu Expand Document (external link)

CarrierWave

In this article we will discuss the process of how to upload an image using carrierwave.

Table Of Contents

  1. What is CarrierWave?
  2. How to install carrierwave
  3. Usage

What is CarrierWave?

CarrierWave is a gem that provides a simple and extremely flexible way to upload files from Ruby applications. It works well with Rack based web applications, such as Ruby on Rails.

How to install carrierwave

Reminder:

Make sure that your containers are up and running.

In your Gemfile, add gem carrierwave.

 gem 'carrierwave'

Then run bundle install.

 root@0122:/usr/src/app# bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching carrierwave 2.2.3
Installing carrierwave 2.2.3
Bundle complete! 17 Gemfile dependencies, 79 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

Usage

To use the carrierwave image upload, you need to generate the uploader file.

 root@0122:/usr/src/app# rails generate uploader Image
      create  app/uploaders/image_uploader.rb

Read Carefully:

You can set an allowlist of acceptable extensions or content types in CarrierWave. If you are mounting the uploader, uploading a file with the incorrect extension will render the record invalid. Otherwise, an error message is displayed.

Uncomment the extension_allowlist method on your ImageUploader. The only allowed file extensions are jpg, jpeg, gif, and png.

# app/uploaders/image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base
  # ...
  # 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
  # ...
  # For images you might use something like this:
- # def extension_allowlist
- #   %w(jpg jpeg gif png)
- # end
+ def extension_allowlist
+   %w(jpg jpeg gif png)
+ end
  # ...
end

Read Carefully:

You may use different kinds of storage in carrierwave, such as “filesystem” or “cloud storage”, all you need to do is specify the storage in your uploader, in our case, it’s storage :file for filesystem. You may also indicate where the uploaded files should be saved with the use of method store_dir. See the ImageUploader above for reference.

To explain what happens here, the uploaded file will be stored in the filesystem, meanwhile, only the file directory (string) will be saved on your database (column where you mounted the uploader).

To do that, let’s add image column with type string to our posts table.

 root@0122:/usr/src/app# rails g migration AddImageToPosts image:string
      invoke  active_record
      create    db/migrate/xxxxxxxxxxxxxx_add_image_to_posts.rb
 root@0122:/usr/src/app# rails db:migrate
== xxxxxxxxxxxxxx AddImageToPosts: migrating ==================================
-- add_column(:posts, :image, :string)
   -> 0.0076s
== xxxxxxxxxxxxxx AddImageToPosts: migrated (0.0078s) =========================

Mount the ImageUploader to your image column in post model.

# app/models/post.rb

class Post < ApplicationRecord
  # ...
  belongs_to :user
+ mount_uploader :image, ImageUploader
  # ...
end

On your posts form, add file field for image.

<!-- app/views/posts/_form.html.erb -->
<%= form_with model: post do |form| %>
  <!-- ... -->
+ <div>
+   <%= form.file_field :image %>
+ </div>
  <%= form.submit %>
<% end %>

Permit image parameter on PostsController.

# app/controllers/posts_controller.rb

class PostsController < ApplicationController
  # ...
  private
  # ...
  def post_params
-   params.require(:post).permit(:title, :content, :image)
+   params.require(:post).permit(:title, :content, :image, category_ids: [])
  end
  # ...
end

Finally, display the image to your posts index page.

<!-- app/views/posts/index.html.erb -->

<!-- ... -->
  <td>comments count</td>
+ <td>image</td>
  <td>action</td>
  </thead>
  <% @posts.each do |post| %>
    <!-- ... -->
    <td><%= post.comments_count %></td>
+   <td><%= image_tag post.image.url if post.image.present? %></td>
<!-- ... -->

Reminder:

Before the image_tag method, we must include a condition (if post.image.present?) that checks whether the image exists. Otherwise, an error will occur if the post does not have an image since you are giving a nil url on image_tag method.

An illustration of such error is shown below.

Now we already integrated the image upload in our application.

Before you commit the changes that you’ve made during the course of this tutorial, you should take note that the uploaded images should not be committed and push to your remote repository since we don’t need it in our codebase. But if we take a look at the current uncommitted changes:

 $~/KodaCamp> git status -u                                                                                                                                                       ✔  11:41:14  
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        public/uploads/post/image/xx/xxxx.png

nothing added to commit but untracked files present (use "git add" to track)

You will see that the uploaded images can be seen in the untracked files. Meaning you and the other developers that have access to your project can commit and push the uploaded images to your remote repository even though these files are not needed. This will cause confusion and inconvenience to you and to those developers. So we have to make a restriction that prevents everyone from committing uploaded files. To do this, we should add the directory to which the uploaded images are stored in our .gitignore file.

# .gitignore

# ...
  /public/assets
+ /public/uploads
# ...

A gitignore file specifies intentionally untracked files that Git should ignore. Files already tracked by Git are not affected. So if you want to ignore a file that you’ve committed in the past, you’ll need to delete the file from your repository and then add a .gitignore rule for it. In our case any files stored in /public/uploads will be ignored by git.

Let’s check our untracked changes again.

 $~/KodaCamp> git status -u                                                                                                                                           ✔  11m 34s   13:31:35  
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   .gitignore

no changes added to commit (use "git add" and/or "git commit -a")

The uploaded images are now ignored by Git.


Back to top

Copyright © 2020-2022 Secure Smarter Service, Inc. This site is powered by KodaCamp.