Topics Covered in This Ruby on Rails Tutorial:
Configuring Active Storage, Configuring Image Processing, Modifying the Form, Customizing Images
Exercise Overview
In this comprehensive exercise, we'll transform your Rails admin interface by implementing dynamic image handling for each product. You'll learn to configure Active Storage—Rails' powerful file attachment framework—and integrate it seamlessly with your admin forms to replace static placeholder images with customizable, properly-sized product images.
If you completed the previous exercise, you can skip the following sidebar. We strongly recommend completing the previous exercise (8A) before starting this one, as it establishes the foundational admin interface we'll be enhancing. If you haven't finished it, follow the setup instructions below.
Tutorial Progress Flow
1Setup Active Storage
Configure Rails framework and install required dependencies for image processing
2Modify Admin Forms
Customize Active Admin interface to handle file uploads with proper validation
3Implement Image Display
Replace static images with dynamic product-specific images across all views
If You Did Not Do the Previous Exercise (8A)
- Close any files you may have open.
- Open the Finder and navigate to Class Files > yourname-Rails Class
- Open Terminal.
- Type
cdand a single space (do NOT press Return yet). - Drag the yourname-Rails Class folder from the Finder to the Terminal window and press ENTER.
- Run
rm -rf nuttyto delete your copy of the nutty site. - Run
Git clone https://bitbucket.org/Noble Desktop/nutty.Gitto copy the That Nutty Guy Git repository. - Type
cd nuttyto enter the new directory. - Type
Git checkout 8Ato bring the site up to the end of the previous exercise. - Run
bundleto install any necessary gems. - Run
yarn install—check-filesto install JavaScript dependencies.
Environment Setup Requirements
Ensures you have the correct starting point for this exercise
Installs all required Ruby gems specified in the Gemfile
Sets up frontend asset pipeline and JavaScript libraries
Positions codebase at the exact completion point of previous exercise
Introducing Active Storage
Now we'll tackle the challenge of replacing those repetitive Tinfoil Hat images with unique, properly-managed product images using Rails' sophisticated file handling system.
Rails provides enterprise-grade file attachment capabilities through Active Storage, a framework that has revolutionized how Rails applications handle media files since its introduction in Rails 5.2. Active Storage excels at cloud storage integration—seamlessly working with Amazon S3, Google Cloud Storage, and Microsoft Azure—while maintaining excellent performance with local disk storage for development environments. In this exercise, we'll start with local storage and explore cloud deployment options when we deploy to production environments later in the course.
One of Active Storage's most powerful features is automatic image processing and variant generation. This means you can dynamically create thumbnails, resize images, and apply transformations without manual intervention. To unlock this functionality, we'll install ImageMagick—the industry-standard image manipulation library—and integrate the image_processing gem into our application.
ImageMagick is a battle-tested, cross-platform image processing powerhouse that handles everything from simple resizing to complex transformations like cropping, rotation, format conversion, and color adjustment. Install it via Homebrew with this Terminal command:
brew install imagemagickNext, we'll add the Ruby gem that interfaces with ImageMagick. Open your Gemfile, scroll to the bottom, and add this dependency:
# Resize image attachments gem 'image_processing'Save the file to ensure your changes are preserved.
Return to Terminal and run the bundle command to install the new gem:
bundleRemember: whenever you add new gems to your application, the Rails server must be restarted to load the new dependencies.
Switch to the ruby tab in your Terminal window (where the server is running).
Stop the server with CTRL–C.
Restart the server to load your new gem:
rails sNow we'll initialize Active Storage's database infrastructure. In a separate Terminal window, execute these commands:
rails active_storage:install rails db:migrateThese commands create the specialized database tables that Active Storage requires for tracking file attachments, their metadata, and associated variants.
Let's examine Active Storage's configuration by opening config > storage.yml. This file contains environment-specific storage settings:
test: service: Disk root: <%= Rails.root.join("tmp/storage") %> local: service: Disk root: <%= Rails.root.join("storage") %>Notice that the default service for local development is "Disk"—exactly what we need for this exercise. Files uploaded through your application will be stored in the "storage" directory within your Rails project root. The configuration file also includes sample setups for production-grade services like Amazon S3, Google Cloud Storage, and Microsoft Azure, which you'll likely use in production deployments.
Close the configuration file—the defaults work perfectly for our current needs.
With Active Storage configured, we need to update our Product model to recognize its image attachment capability.
Open nutty > app > models > product.rb in your code editor.
Add the Active Storage association at the bottom of the model class:
class Product < ActiveRecord::Base validates :title, :sku, :price, presence: true validates :price, numericality: true has_one_attached :image endThis single line of code establishes a powerful connection between your Product model and Active Storage, enabling each product to have an associated image with full processing capabilities.
Save the file to commit your model changes.
Active Storage is optimized for cloud storage systems like Amazon S3 and Microsoft Azure, but works equally well with local disk storage for development environments.
Active Storage Installation Process
Install ImageMagick
Run 'brew install imagemagick' to add image processing capabilities to your system
Add image_processing Gem
Include the gem in Gemfile and run bundle to enable image transformation features
Initialize Active Storage
Execute 'rails active_storage:install' and migrate database to create required tables
Modifying the Form
With our backend configured, we'll now enhance the Active Admin interface to support file uploads, creating an intuitive admin experience for managing product images.
Navigate to the admin interface in your browser: localhost:3000/admin
If prompted, sign in with the credentials you created in the previous exercise. If you encounter login issues, use this troubleshooting solution:
“has_one_attached :image
This single line of code in the Product model establishes the Active Storage association, enabling file attachment capabilities for product images.Default Admin BehaviorWhen Active Admin files are blank, default behavior is assumed. To customize forms, you must explicitly define the form structure using Arbre syntax.
Creating a Login
- Open a Rails console by typing:
rails c - Execute this command to create a fresh admin user:
AdminUser.destroy_all
AdminUser.create(email: 'admin@example.com', password: 'password')
- Type
exitto leave the Rails console. - You can now log in with email admin@example.com and password password.
Click the Products link in the navigation.
Select Edit next to any product to access the form we'll be customizing.
Open nutty > app > admin > products.rb in your code editor.
Active Admin operates on a convention-over-configuration principle: when admin files are minimal, it generates default behavior automatically. Since products.rb is essentially empty, Active Admin creates a basic CRUD interface. To add our custom file upload functionality, we need to explicitly define the form structure.
permit_params must be configured to specify which form fields are allowed for submission. This prevents unauthorized users from modifying restricted fields.
Arbre
Active Admin uses Arbre, an elegant domain-specific language for building HTML interfaces. Arbre provides object-oriented HTML generation that's both intuitive and powerful, allowing you to create sophisticated admin interfaces with minimal code.
For comprehensive documentation, visit: GitHub.com/gregbell/arbre
Below the commented code block, add this form structure:
# end
form do |f|
end
endWithin the form block, create input fields for all product attributes:
form do |f|
f.inputs "Product Details" do
f.input :title
f.input :sku
f.input :price
f.input :description
f.input :specs
end
f.actions
endLet's improve the user experience by making the SKU label more professional and clear:
f.input :sku, label: "SKU"Save the file and reload the Edit Product page to see your improved form.
We can enhance usability further by adding contextual help text. Update the SKU field:
f.input :sku, label: "SKU", hint: "A unique SKU for this product. Very important!"Save and reload to see the helpful hint text appear below the field.
You may notice that the price field displays increment/decrement arrows in some browsers. For decimal currency values, a standard text input provides better user experience. Modify the price field:
f.input :price, as: :string
The as: parameter allows you to override Active Admin's default field type selection, giving you precise control over form behavior.
Save the file and reload to confirm the price field now behaves as a standard text input.
Return to your code editor to add the image upload functionality.
Form Customization Features
Custom Labels
Override default field labels using the label parameter to display more user-friendly text like 'SKU' instead of 'sku'.
Helper Text
Add contextual hints below form fields using the hint parameter to guide users with important information.
Field Types
Control input types with the 'as' parameter to optimize user experience, such as using string inputs for decimal values.
Customizing Product Images
Now comes the exciting part—integrating image uploads and creating dynamic, responsive product displays that automatically handle sizing and optimization.
Add the image upload field to your form (around line 21):
form do |f| f.inputs "Product Details" do f.input :title f.input :sku, label: "SKU", hint: "A unique SKU for this product. Very Important!" f.input :image, as: :file f.input :price, as: :string f.input :description f.input :specs endSave and reload the Edit Product page—you'll see the file upload field has appeared!
Before we can use this form, we need to configure Active Admin's security parameters. Examine the commented code in products.rb for context.
Rails implements strong parameters as a security mechanism, requiring explicit permission for form fields to prevent unauthorized data manipulation. We must configure Active Admin to accept our new image field through the
permit_paramsdirective.Replace all commented code with this security configuration:
ActiveAdmin.register Product do permit_params :title, :description, :specs, :sku, :price, :image form do |f|Save the file and reload the Edit Product page.
Click Choose File or Browse next to the Image field.
Navigate to: Desktop > Class Files > yourname-Rails Level 2 Class > That Nutty Guy HTML > img > product_images.
Select the appropriate image for the product you're editing.
Click Update Product at the bottom of the form.
You'll be redirected to the product's show page. The image isn't visible yet because we need to customize the display template—let's fix that next.
Return to products.rb and add a custom show page configuration:
permit_params :title, :description, :specs, :sku, :price, :image show do attributes_table do end form do |f|Define which product attributes should appear in the show page:
show attributes_table do row :title row :sku row :price row :description row :specs end active_admin_comments endThe
active_admin_commentsmethod preserves Active Admin's built-in commenting functionality for collaborative admin workflows.Add the image display at the top of the attributes table:
attributes_table do row :image row :title row :sku row :price row :description row :specs endSave and reload the product page. You'll see "image" text appears, but we need to render the actual image.
Update the image row with proper display logic:
attributes_table do row :image do image_tag url_for(product.image) if product.image.attached? end row :title row :sku row :price row :description row :specs endWhen you need custom content in a table row, wrap it in a
do…endblock. The url_for() helper converts Active Storage's file object into a browser-accessible URL, while the conditional check ensures we only display images when they exist.Save and reload—your image now appears! However, it's likely enormous and needs resizing.
Implement responsive image sizing using Active Storage's variant system:
image_tag url_for(product.image.variant(resize: "200x200"))Reload the page to see your properly-sized image. The variant method leverages ImageMagick to create optimized image versions on-demand. The resize parameter maintains aspect ratio while fitting the image within the specified dimensions, preventing distortion.
Now let's replace the static product images in the main catalog. Open nutty > app > views > products > index.html.erb
Locate this static image tag around line 9:
<img id="bill" class="" src="img/product_images/tinfoil-hat.jpg" ALT="Tinfoil Hat"></a>Replace it with dynamic image rendering:
<%= link_to product do %> <% if product.image.attached? %> <%= image_tag url_for(product.image.variant(resize_to_limit: [500,500])), ALT: product.title %> <% end %> <p class="product"><%= product.title %></p> <% end %>Save the file and navigate to localhost:3000 in your browser.
Excellent! The static placeholder images are gone, replaced by the actual product image you uploaded. The other products will display their images once you upload them in subsequent exercises.
Click on your edited product to view its individual page—notice we still need to update this view as well.
Open nutty > app > views > products > show.html.erb and locate this static image tag around line 17:
<img class="product" src="/img/product_images/tinfoil-hat.jpg" ALT="<%= @product.title %>">Replace it with responsive image display code:
<div class="visible-xs"> <h1><%= @product.title %></h1> <p class="gray-text">Item #<%= @product.sku %></p> <hr> </div> <% if @product.image.attached? %> <%= image_tag url_for(@product.image.variant(resize_to_limit: [700,900])), ALT: @product.title, class: 'product' %> <% end %> </div> <!—/column1—>Save the file and reload the product page to see your properly-sized, dynamic product image in action!
Keep both browser tabs open and the server running—we'll build upon this image management system in the next exercise.
Image Resize Methods
| Feature | resize | resize_to_limit |
|---|---|---|
| Behavior | Fits within exact dimensions | Respects maximum dimensions |
| Aspect Ratio | Maintained without distortion | Original proportions preserved |
| Use Case | Admin thumbnails (200x200) | Product displays (700x900) |
Image Integration Workflow
Upload via Admin
Use the file input field to upload product images through the Active Admin interface
Configure Display
Set up show page with attributes_table and image_tag helpers for proper image rendering
Replace Static Images
Update view templates to use dynamic Active Storage URLs instead of hardcoded image paths