1. Code
  2. Ruby
  3. Ruby on Rails

Rails Image Upload: Using CarrierWave and Devise

Scroll to top

In the first part of this series, you learned how to use CarrierWave in your Rails application. In this second part, you will learn how to enable image uploading for your users using Devise. Devise is an authentication solution for Rails. You will also learn how to use fog, a Ruby cloud service library that will enable your application to connect to Amazon Web Services.

Enough talk—let’s get down to business.

Rails Application Setup

Generate your new rails application:

1
2
rails new myapp

Open up your Gemfile and add the following gems:

1
2
***Gemfile***
3
4
gem carrierwave
5
gem devise
6
gem mini_magick
7
gem fog

Run bundle install to install the gems.

From your terminal, create a Pages controller:

1
2
rails g controller Pages index

Navigate to config/routes.rb and add a root path:

1
2
***config/routes.rb***
3
4
root to: 'pages#index'

Generate and Configure Devise

The uploading feature will be integrated into our User model for users to upload avatars. From your terminal, install devise:

1
2
rails generate devise:install

The generator will install an initializer which describes all of Devise’s configuration options. Open up app/views/layouts/application.html.erb in your text editor and add the following code above the yield block:

1
2
***app/views/layouts/application.html.erb***
3
4
5

At this point you can generate your User model:

1
2
rails generate devise User

Next, migrate your database:

1
2
rake db:migrate

You will need to edit devise views, so it is important you generate those:

1
2
rails generate devise:views

And that will do the magic.

Using your text editor, open app/views/devise/registrations/new.html.erb and edit it to look like this:

1
2
***app/views/devise/registrations/new.html.erb***
3
4
Sign up
5
6
 {multipart: :true}) do |f| %>
7
  
8
9
  
10
    
11
    
12
  
13
14
  
15
    
16
    
17
    ( characters minimum)
18
    
19
    
20
  
21
22
  
23
    
24
    
25
  
26
27
  
28
    
29
      
30
      
31
    
32
  
33
34
  
35
    
36
  
37
38
39

Do the same for app/views/devise/registrations/edit.html.erb:

1
2
***app/views/devise/registrations/edit.html.erb***
3
4
Edit 
5
6
7
  
8
9
  
10
    
11
    
12
  
13
14
  
15
    Currently waiting confirmation for: 
16
  
17
18
  
19
     (leave blank if you don't want to change it)
20
    
21
  
22
23
  
24
    
25
    
26
  
27
28
  
29
    
30
    
31
      
32
    
33
  
34
  
35
  
36
37
  
38
     (we need your current password to confirm your changes)
39
    
40
  
41
42
  
43
    
44
  
45
46
47
Cancel my account
48
49
Unhappy? 
50
51

With that done, you will need to whitelist avatar for devise and add an avatar column to the User table. From your terminal, run migration to add a new avatar column.

1
2
3
rails g migration add_avatar_to_users avatar:string
4
rake db:migrate

Add the CarrierWave avatar to your User model—your model should look like this:

1
2
***models/user.rb***
3
4
class User < ActiveRecord::Base
5
  mount_uploader :avatar, AvatarUploader
6
7
  devise :database_authenticatable, :registerable,
8
         :recoverable, :rememberable, :trackable, :validatable
9
10
  # User Avatar Validation
11
  validates_integrity_of  :avatar
12
  validates_processing_of :avatar
13
14
  private
15
    def avatar_size_validation
16
      errors[:avatar] << "should be less than 500KB" if avatar.size > 0.5.megabytes
17
    end
18
end

In the above code, you added a mount_uploader line at the top of the User class. There is also a validation to check the integrity and processing of the avatar, alongside a method to ensure that no image greater than 500KB is uploaded.

You need to add avatar, avatar_cache, and remove_avatar to the list of accessible attributes. Doing this is easy—just open up your application_controller.rb and make it look like this:

1
2
***app/controllers/application_controller.rb***
3
4
class ApplicationController < ActionController::Base
5
  # Prevent CSRF attacks by raising an exception.
6
  # For APIs, you may want to use :null_session instead.
7
  protect_from_forgery with: :exception
8
9
  before_action :configure_permitted_parameters, if: :devise_controller?
10
11
  protected
12
13
  def configure_permitted_parameters
14
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me, :avatar, :avatar_cache) }
15
    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :password, :password_confirmation, :current_password, :avatar, :avatar_cache, :remove_avatar) }
16
  end
17
end

With that done, you are ready to integrate CarrierWave.

Setting Up CarrierWave

Using your text editor, navigate to config/initializers and create a file named carrier_wave.rb. Paste in the code below:

1
2
***config/initializers/carrier_wave.rb***
1
2
require 'carrierwave/orm/activerecord'

This is the initializer that is needed in loading CarrierWave after ActiveRecord.

From your terminal, generate an uploader:

1
2
rails generate uploader Avatar

This will create a new directory called uploaders in the app folder and a file inside called avatar_uploader.rb. I have edited the contents of the file to look like what I have below:

1
2
3
***app/uploaders/avatar_uploader.rb***
4
5
# encoding: utf-8
6
7
class AvatarUploader < CarrierWave::Uploader::Base
8
9
  include CarrierWave::MiniMagick
10
11
  # Choose what kind of storage to use for this uploader:
12
  storage :fog
13
14
  # Override the directory where uploaded files will be stored.
15
  # This is a sensible default for uploaders that are meant to be mounted:
16
  def store_dir
17
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
18
  end
19
20
  # Create different versions of your uploaded files:
21
  version :thumb do
22
    process :resize_to_fill => [100, 100]
23
  end
24
25
  version :medium do
26
    process :resize_to_fill => [300, 300]
27
  end
28
29
  version :small do
30
    process :resize_to_fill => [140, 140]
31
  end
32
33
  # Add a white list of extensions which are allowed to be uploaded.
34
  # For images you might use something like this:
35
  def extension_white_list
36
    %w(jpg jpeg gif png)
37
  end
38
end

You need the MiniMagick line to generate different versions of an image. I included three versions of images. MiniMagick makes the resizing into this version possible. The last code block ensures that no file extensions aside from those listed here are uploaded.

AWS Setup

For this tutorial, we will be uploading our images to Amazon Web Services. If you do not have an account yet, hop over to the sign-up page and create a free account.

When you’ve finished with that, you will need to create a bucket to store your images. When there, choose Create Bucket to open the dialog box. Enter a name for the bucket and select a region. When done, select Create.

Open your Gemfile and add this gem, and bundle install when done.

1
2
gem 'figaro'

From your terminal, run bundle exec figaro install. This will a create a new file config/application.yml and append it to your application’s .gitignore. You need this file to keep your AWS access id and secret key safe.

To find your AWS access id and secret key, go to Amazon Web Services and click on the name of your account, which is located in the right corner of the console.

From the drop-down, select Security Credentials, and click the Continue to Security Credentials button. In the page that shows, select Access Keys (Access Key ID and Secret Access Key). Click on the Create New Access Key button to generate a new key, and copy it into an editor.

In your text editor, navigate to config/application.yml and paste in the following:

1
2
***config/application.yml***
3
4
aws_access_id: Enter access_id here
5
aws_access_secret_key: Enter access_key here

Replace the lines as stated above.

Navigate to config/initializers, create a file named storage.rb, and paste in the following:

1
2
***config/initializers/storage.rb***
3
4
CarrierWave.configure do |config|
5
  config.storage = :fog
6
  config.fog_credentials = {
7
      provider:              'AWS',
8
      aws_access_key_id:     ENV["aws_access_id"],
9
      aws_secret_access_key: ENV["aws_access_secret_key"],
10
      region: 'us-west-2'
11
  }
12
  config.fog_directory  = "tutsplus-avatar"
13
  config.fog_public     = false
14
end

According to the above config, the region for my bucket is us-west-2, and the bucket’s name is tutsplus-avatar. Replace that with information about your bucket.

Start up your rails server and point your browser to https://localhost:3000/users/sign_up.

Setting a Default Avatar

In your application, you might want to set a default avatar for users that choose not to upload an avatar. Doing this is easy.

Create a folder in app/assets/images called fallback and drop your default image in it. Using your text editor, navigate to app/uploaders/avatar_uploader.rb and paste in the code below:

1
2
***app/uploaders/avatar_uploader.rb***
3
4
def default_url(*args)
5
  ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default-avatar.gif"].compact.join('_'))
6
end

Be sure to change default-avatar.gif to the name of your image.

Conclusion

Now you know how to enable image uploading for your users. This adds an important feature to your rails application. I hope you had fun. In the next part, we will have a look at PaperClip. Your feedback is welcome.

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.