Ruby on Rails – File Uploading



You may have a requirement in which you want your site visitors to upload a file on your server. Rails makes it very easy to handle this requirement. Now we will proceed with a simple and small Rails project.

As usual, let's start off with a new Rails application called FileUploadapp. Let's create the basic structure of the application by using simple rails command.

rails new FileUploadapp cd FileUploadapp

Before starting application development, we should install gem files. Open up your Gemfile and add the following two gems at the bottom.

gem 'carrierwave', '~> 3.0' gem install bootstrap-sass

After adding gems in, we need to run the following command −

bundle install

The command terminal shows the following log −

Resolving dependencies... Fetching mini_magick 5.2.0 Fetching ssrf_filter 1.2.0 Fetching ffi 1.17.1 (x64-mingw-ucrt) Installing ssrf_filter 1.2.0 Installing mini_magick 5.2.0 Installing ffi 1.17.1 (x64-mingw-ucrt) Fetching ruby-vips 2.2.3 Installing ruby-vips 2.2.3 Fetching image_processing 1.14.0 Installing image_processing 1.14.0 Fetching carrierwave 3.1.1 Installing carrierwave 3.1.1 Bundle complete! 22 Gemfile dependencies, 125 gems now installed.

What is CarrierWave?

CarrierWave is a file uploader library for Rails. It handles file uploads through forms, and stores files locally or in the cloud (e.g., Amazon S3). With the help of libraries like MiniMagick, it allows you to process and resize images, and gives you more control over file paths, naming, and structure.

You need to configure CarrierWave by adding the following settings in config\initializers\carrierwave.rb

require "carrierwave" require "carrierwave/orm/activerecord" CarrierWave.configure do |config| config.root = Rails.root.join("public") # Ensures uploads go to /public/uploads config.cache_dir = "tmp/uploads" end

Note that by default, CarrierWave stores uploaded files in −

public/uploads/

Generate Uploader

Now we need to create an uploader. An Uploader came from carrierWave gem and it tells to carrierwave how to handle the files. In short, it contained all file processing functionalities. Run the command to create an uploader as shown below.

rails generate uploader ProfilePicture

This creates app/uploaders/profile_picture_uploader.rb.

class ProfilePictureUploader < CarrierWave::Uploader::Base # Choose what kind of storage to use for this uploader: storage :file def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end end

Generate User Scaffold

Let us create the User model, the controller and the required views with the scaffold command −

rails generate scaffold User username:string email:string profile_picture:string rails db:migrate

Mount the Uploader

Open the User model (app/models/user.rb) and call the uploader as shown below −

class User < ApplicationRecord mount_uploader :profile_picture, ProfilePictureUploader end

Also, make sure that the user input Only allows a list of trusted parameters through.

def user_params params.require(:user).permit(:username, :email, :profile_picture) end

Update the Views

Edit the _form.html.erb file to add the File field to let the user choose profile picture −

<%= form_with(model: user) do |form| %> <% if user.errors.any? %> <div style="color: red"> <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2> <ul> <% user.errors.each do |error| %> <li><%= error.full_message %></li> <% end %> </ul> </div> <% end %> <div> <%= form.label :username, style: "display: block" %> <%= form.text_field :username %> </div> <div> <%= form.label :email, style: "display: block" %> <%= form.text_field :email %> </div> <div> <%= form.label :profile_picture, style: "display: block" %> <%= form.text_field :profile_picture %> </div> <div class="field"> <%= form.label :profile_picture %> <%= form.file_field :profile_picture %> </div> <div> <%= form.submit %> </div> <% end %>

Similarly, modify the show.html.erb file.

<p style="color: green"><%= notice %></p> <p> <strong>Username:</strong> <%= @user.username %> </p> <p> <strong>Email:</strong> <%= @user.email %> </p> <% if @user.profile_picture? %> <p> <strong>Profile Picture:</strong><br> <%= image_tag @user.profile_picture.url, width: 150, height: 150 %> </p> <% else %> <p>No profile picture uploaded.</p> <% end %> <div> <%= link_to "Edit this user", edit_user_path(@user) %> | <%= link_to "Back to users", users_path %> <%= button_to "Destroy this user", @user, method: :delete %> </div>

That’s it. Now start the server and visit http://localhost:3000/users/new to open up the user registration form.

Update the Views

Click on the choose File button, navigate to the desired file and then click Create User button. Rails responds with a confirmation page, displaying the profile picture you uploaded.

Update the View

CarrieerWave vs Active Storage

In Rails 6 and onwards, the Active Storage framework was added which can natively handle file uploads. Here is a comparison of handling uploads with CarrierWave and Active Storage:

Feature Active Storage CarrierWave
Built into Rails Yes (since Rails 6) No (requires separate gem)
Setup complexity Simple, plug-and-play More configurable, but requires boilerplate
File storage structure Managed internally (in storage/) You control the structure (e.g., /uploads/users/)
Image processing On-demand variants (using MiniMagick/Vips) Immediate, during upload (using MiniMagick)
Metadata storage In database (active_storage_blobs) Typically stored in model columns or filenames
Cloud storage support Yes Yes
Attachment declaration has_one_attached, has_many_attached You mount uploaders in models
Preview/caching support Built-in previews Needs custom logic or plugins
Advertisements