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 newFileUploadapp 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.0Fetching ssrf_filter 1.2.0Fetching ffi 1.17.1(x64-mingw-ucrt)Installing ssrf_filter 1.2.0Installing mini_magick 5.2.0Installing ffi 1.17.1(x64-mingw-ucrt)Fetching ruby-vips 2.2.3Installing ruby-vips 2.2.3Fetching image_processing 1.14.0Installing image_processing 1.14.0Fetching carrierwave 3.1.1Installing carrierwave 3.1.1Bundle complete!22Gemfile 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.
classProfilePictureUploader<CarrierWave::Uploader::Base# Choose what kind of storage to use for this uploader: storage :filedefstore_dir"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"endend
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 −
classUser<ApplicationRecord mount_uploader :profile_picture,ProfilePictureUploaderend
Also, make sure that the user input Only allows a list of trusted parameters through.
defuser_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>
<div><%= form.label :username, style: "display: block" %><ul> <% user.errors.each do |error| %> <li><%= error.full_message %></li><%end%> </ul></div><%end%>
</div><div><%= form.label :email, style: "display: block" %><%= form.text_field :username%>
</div><div><%= form.label :profile_picture, style: "display: block" %><%= form.text_field :email%>
</div><div class="field"><%= form.label :profile_picture %><%= form.text_field :profile_picture%>
</div><div><%= form.submit %> </div><%end%><%= form.file_field :profile_picture%>
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></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><%= image_tag @user.profile_picture.url, width: 150, height: 150 %>
Thatâs it. Now start the server and visit http://localhost:3000/users/new to open up the user registration form.

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.

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 |
Leave a Reply