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 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? %>
&lt;div style="color: red"&gt;&lt;h2&gt;&lt;%= pluralize(user.errors.count, "error") %&gt; prohibited this user from being saved:&lt;/h2&gt;
  &lt;ul&gt;
    &lt;% user.errors.each do |error| %&gt;
      &lt;li&gt;&lt;%= error.full_message %&gt;&lt;/li&gt;&lt;%end%&gt;
  &lt;/ul&gt;&lt;/div&gt;&lt;%end%&gt;
<div><%= form.label :username, style: "display: block" %>
&lt;%= form.text_field :username%&gt;
</div><div><%= form.label :email, style: "display: block" %>
&lt;%= form.text_field :email%&gt;
</div><div><%= form.label :profile_picture, style: "display: block" %>
&lt;%= form.text_field :profile_picture%&gt;
</div><div class="field"><%= form.label :profile_picture %>
&lt;%= form.file_field :profile_picture%&gt;
</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>
&lt;%= image_tag @user.profile_picture.url, width: 150, height: 150 %&gt;
</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:

FeatureActive StorageCarrierWave
Built into RailsYes (since Rails 6)No (requires separate gem)
Setup complexitySimple, plug-and-playMore configurable, but requires boilerplate
File storage structureManaged internally (in storage/)You control the structure (e.g., /uploads/users/)
Image processingOn-demand variants (using MiniMagick/Vips)Immediate, during upload (using MiniMagick)
Metadata storageIn database (active_storage_blobs)Typically stored in model columns or filenames
Cloud storage supportYesYes
Attachment declarationhas_one_attached, has_many_attachedYou mount uploaders in models
Preview/caching supportBuilt-in previewsNeeds custom logic or plugins

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *