When storing static files in Rails, the first toolsets I reach for are 3rd party gems like: CarrierWave or Paperclip (before they deprecated it in favour of Active Storage). Active Storage was introduced with Rails 5.2.
Active Storage facilitates uploading files to a cloud storage service like Amazon S3, Google Cloud Storage, or Microsoft Azure Storage and attaching those files to Active Record objects. It comes with a local disk-based service for development and testing and supports mirroring files to subordinate services for backups and migrations.
Using Active Storage, an application can transform image uploads with ImageMagick, generate image representations of non-image uploads like PDFs and videos, and extract metadata from arbitrary files.
In this article, we will focus on how to make the validation of active storage's files by creating a simple app.
Go in the terminal and generate a new app
rails new app
After cd in the app folder crated, let's generate a simple blog app with the scaffold command.
rails g scaffold Post title:string content:text
When the process finished don't forget to migrate
rails db:migrate
We can lunch the server now
rails server
And by visiting the
localhost:3000/posts/index
in our browser, we can see the application running. Let's set the routes to posts/index by editing the
config/routes.rb
file #config/routes.rb
Rails.application.routes.draw do
resources :posts
root to: 'posts#index'
end
Let's now add the image to our Post with active storage.
Set up
First, we need to install active storage in our project. We will need to run this command on the terminal lines
rails active_storage:install
After running this command, Rails generates a migration for you. Upon inspection of that migration, and creates 2 different tables:
active_storage_blobs
is up first, it contains information about files like metadata, filename, checksum, and so on.The next table,
active_storage_attachments
, stores the name of any file attachment as well as the record, which is also a polymorphic association. Why is that important? It allows you to use file attachments on any model without cluttering your model's migrations with table columns specifically for file data.Don't forget to run the migration command At the end
rails db:migrate
Adding the image to the Model, View and Controller
By visiting our
app/models/post.rb
We will attach the image to our post#app/models/post.rb
class Post < ApplicationRecord
has_one_attached :image
end
We will again need to add the image in our controller just at the end in the post_params method add the image to the properties of the model.
#app/controller/posts_controller.rb
def post_params
params.require(:post).permit(:title, :content, :image)
end
We will now go in our views and add the image.
In the
app/views/posts/_form.html.erb
we will be editing the file by adding a new class after the content.#app/views/posts/_form.html.erb
<div class="field">
<%= form.label :image %>
<%= form.file_field :image %>
</div>
Now we need to load the image in the index and show
#app/views/posts/index.html.erb
<% if post.image.attached? %>
<td><%= image_tag post.image %></td>
<% end %>
#app/views/posts/show.html.erb
<p>
<% if @post.image.attached? %>
<%= image_tag @post.image %>
<% end %>
</p>
And voila, we can add the image to the post. But what if we want to have the image associate to each post?
In this case, we will need to validate our image so that the user can not create a post without an image.
Let's first validate our title and content fields
# app/models/post.rb
class Post < ApplicationRecord
has_one_attached :image
validates :title, :content, presence: true
validates :title, length: {minimum:5, maximum:25}
validates :content, length: {minimum:10, maximum:50}
end
By editing our
post.rb
file, we prevent the user to submit an empty title and empty content field. He can't also submit the title with content less than 5 or more than 25 characters, as well as the content, can't have more than 50 or less than 10 characters.Validation with Active Storage
We've now validated our title and content, but we need again to prevent the user to create a post without an image associated with it.
It is very simple, we can do it by adding this one line. But before that, we need first to add the
gem 'active_storage_validations'
in the Gemfile and run bundle install
after. # app/models/post.rb
validates :image, attached: true, content_type: %i[png jpg jpeg]
We prevent the user to add files of types different from png, jpg and jpeg and we say that the image must be attached to the post. So he can't submit a post without an associated image.
Restart the server to see the changes.
Voila, we reach our goal, now the user can not submit a Post with an empty image.