Product Images with Active Storage

Free Ruby on Rails Tutorial

Dive into this comprehensive Ruby on Rails tutorial, covering topics like configuring Active Storage, image processing, modifying the form, and customizing images.

This exercise is excerpted from Noble Desktop’s past web development training materials. Noble Desktop now teaches JavaScript and the MERN Stack in our Full Stack Development Certificate. To learn current skills in web development, check out our coding bootcamps in NYC and live online.

Topics covered in this Ruby on Rails tutorial:

Configuring Active Storage, Configuring Image Processing, Modifying the form, Customizing images

Exercise Overview

In this exercise, we will work on customizing the admin pages and getting each product to display its own image.

  1. If you completed the previous exercise, you can skip the following sidebar. We recommend you finish the previous exercise (8A) before starting this one. If you haven’t finished it, do the following sidebar.

    If You Did Not Do the Previous Exercise (8A)

    1. Close any files you may have open.
    2. Open the Finder and navigate to Class Files > yourname-Rails Class
    3. Open Terminal.
    4. Type cd and a single space (do NOT press Return yet).
    5. Drag the yourname-Rails Class folder from the Finder to the Terminal window and press ENTER.
    6. Run rm -rf nutty to delete your copy of the nutty site.
    7. Run git clone https://bitbucket.org/noble-desktop/nutty.git to copy the That Nutty Guy git repository.
    8. Type cd nutty to enter the new directory.
    9. Type git checkout 8A to bring the site up to the end of the previous exercise.
    10. Run bundle to install any necessary gems.
    11. Run yarn install --check-files to install JavaScript dependencies.

Introducing Active Storage

We need to replace all those copies of the Tinfoil Hat image with each product’s own image.

Full-Stack Web Development Certificate: Live & Hands-on, In NYC or Online, 0% Financing, 1-on-1 Mentoring, Free Retake, Job Prep. Named a Top Bootcamp by Forbes, Fortune, & Time Out. Noble Desktop. Learn More.
  1. Fortunately, Rails provides robust support for file attachments (such as images) through a framework called Active Storage. Active Storage is optimized for hosting files on cloud storage systems such as Amazon S3 or Microsoft Azure Storage, but it works just as well with plain old local disk-based storage too. We’ll use the local disk-based option in this exercise, and explore S3 later on when we deploy to Heroku at the end of this course.

  2. Another awesome feature of Active Storage is the ability to automatically resize images (for example, into thumbnail versions). To take advantage of this feature, we need to add ImageMagick to our system, and the image_processing gem.

  3. ImageMagick is a powerful, cross-platform image editing tool that can resize, crop, rotate, and much more. In Terminal, run the following command to install ImageMagick:

    brew install imagemagick
    
  4. Next, open Gemfile, scroll to the very bottom of the file and add the code:

    # Resize image attachments
    gem 'image_processing'
    
  5. Save the file.

  6. Switch back to Terminal and type:

    bundle
    

    Remember, whenever you install a new gem, you need to stop the Rails server.

  7. Switch to the ruby tab in the Terminal window (the one running the server).

  8. Hit Ctrl–C to stop the server.

  9. Restart the server by typing:

    rails s
    
  10. Next, we need to initialize Active Storage. In another Terminal window, run the following commands:

    rails active_storage:install
    rails db:migrate
    

    These commands create the database tables Active Storage needs to manage its files.

  11. Let’s take a quick peek at the main configuration file for Active Storage: config > storage.yml. Inside this file, you’ll find these lines:

    test:
      service: Disk
      root: <%= Rails.root.join("tmp/storage") %>
    
    local:
      service: Disk
      root: <%= Rails.root.join("storage") %>
    

    Note that for local development, the default service is “Disk”. This is just what we need. Files we upload through the site will go into the “storage” folder inside of Rails.

    There are also sample configs in here for Amazon S3, Google Cloud, and Microsoft Azure. Good to know!

  12. Close the file.

  13. Now that Active Storage is ready to go, we just need to add a bit of code to our model file to let it know that it has an attached image.

  14. In your code editor, open nutty > app > models > product.rb

  15. At the bottom, add the code shown in bold:

    class Product < ActiveRecord::Base
       validates :title, :sku, :price, presence: true
       validates :price, numericality: true
    
       has_one_attached :image
    end
    

    This lets Active Storage know that there’s an attachment field called image associated with this model.

  16. Save the file.

Modifying the Form

Now we need to modify our Active Admin form to accept this file upload.

  1. In a browser, go to: localhost:3000/admin

  2. If prompted, sign in using the email and password you created in the last exercise. If you have trouble logging in, try the following workaround:

    Creating a Login

    1. Open a rails console by typing at the Terminal: rails c
    2. Inside of the Rails console, type the following command and press Enter:
    AdminUser.destroy_all
      AdminUser.create(email: 'admin@example.com', password: 'password')
      
    1. Type exit and press Enter again to leave the Rails console.
    2. You should now be able to log in with email admin@example.com and password password.
  3. At the top, click the Products link.

  4. To the right of any product, click Edit.

  5. In your code editor, open nutty > app > admin > products.rb

    The way that Active Admin files work is if there’s nothing in them, then a bunch of default behavior is assumed. The fact that products.rb is essentially blank means that Active Admin will create its own form. If we want to customize it to create our own form, we need to write some form code of our own.

    Arbre

    The markup language provided throughout Active Admin is called Arbre. Arbre provides object-oriented HTML. Don’t worry–it’s easy to use, and very fast to write.

    If you want more info, go to: github.com/gregbell/arbre

  6. Below the commented out code, add this bold code to create a form:

       # end
    
       form do |f|
       end
    
    end
    
  7. Within the form, add this code to build a set of inputs:

    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
    end
    
  8. There’s a few little things we want to fix in the form. Sku should be all caps. Edit the following line to read:

    f.input :sku, label: "SKU"
    
  9. Save the file.

  10. Reload the Edit Product page in the browser to see your new form with the label in all caps.

  11. We can even add some helper text under the field to assist anyone entering the info. In products.rb in your code editor, add:

    f.input :sku, label: "SKU", hint: "A unique SKU for this product. Very important!"
    
  12. Save the file.

  13. Reload the Edit Product page in the browser to see the hint!

  14. In Chrome or Safari, scroll over the price and notice that some arrows appear to the right of it. Click them to change the price. This doesn’t work so well for our decimal values, so we’d prefer to change the Price field to a string.

  15. In products.rb in your code editor add:

    f.input :price, as: :string
    

    NOTE: If you don’t like the default field type that Active Admin has chosen, as: allows you to specify a different one.

  16. Save the file and reload the Edit Product page in the browser. You’ll see that it becomes a string field.

  17. Switch back to your code editor.

Customizing Product Images

  1. Now we can finally add the code for the image (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
       end
    
  2. Save the file.

  3. Reload the Edit Product page in the browser. Cool! The file upload field appears!

  4. Go back to products.rb in your code editor. Take a look at the commented out code.

    While building model forms on the Flix site, we talked about strong parameters. In our controller, we had to specify which fields were allowed to be submitted through our form. This is a security feature to prevent users from altering fields they shouldn’t have access to. We need to make Active Admin aware of these parameters in the same way. We can do this with permit_params.

  5. The commented out code gives us hints for what code we need, but let’s replace it. Replace all the commented out code with the following bold code:

    ActiveAdmin.register Product do
       permit_params :title, :description, :specs, :sku, :price, :image
    
       form do |f|
    
  6. Save the file.

  7. Reload the Edit Product page in the browser.

  8. To the right of Image click Choose File or Browse.

  9. Navigate to: Desktop > Class Files > yourname-Rails Level 2 Class > That Nutty Guy HTML > img > product_images.

  10. Double–click the appropriate image for the product you are editing to choose it.

  11. At the bottom of the Edit Product page, click Update Product.

    We’re taken to the show page for the product. No image appears yet. We’ll take care of that by customizing the show page.

  12. Go back to products.rb in your code editor and add the following bold code to set up a table where we can specify which product details we want to appear:

    permit_params :title, :description, :specs, :sku, :price, :image
    
    show do
       attributes_table do
       end
    end
    
    form do |f|
    
  13. Now we can add rows for each piece of info. Type:

    show
       attributes_table do
          row :title
          row :sku
          row :price
          row :description
          row :specs
       end
       active_admin_comments
    end
    

    NOTE: active_admin_comments preserves the comment form.

  14. Now let’s add the image code:

    attributes_table do
       row :image
       row :title
       row :sku
       row :price
       row :description
       row :specs
    end
    
  15. Save the file.

  16. Reload the Product page in the browser.

    Oh, the text “image” appears but that’s not what we wanted!

  17. Go back to products.rb in your code editor and edit the code as shown:

    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
    end
    

    NOTE: When you want to display more in a row than just the default, just add a do...end loop. The url_for() helper takes the Active Storage object in product.image and converts it to a URL for display.

  18. Save the file.

  19. Reload the Product page in the browser. Finally, our image appears! But…it’s huge! Here’s where the image_processing gem comes in handy. Change the line as follows:

    image_tag url_for(product.image.variant(resize: "200x200"))
    

    Reload the page and the image should be looking much nicer. To unpack this syntax a bit, variant tells Active Storage to create a new variant of the original image. resize resizes an image to fit with the specified dimensions (“[width]x[height]”) without stretching or distorting it. Neat!

    Now we need to get rid of the terrifying legion of Tinfoil Hat images and get the individual product images to display.

  20. In your code editor, open nutty > app > views > products > index.html.erb

  21. Around line 9, select the following code:

    <img id="bill" class="" src="img/product_images/tinfoil-hat.jpg" alt="Tinfoil Hat"></a>
    
  22. Delete the image tag and replace it with the embedded Ruby code shown in bold:

    <%= 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 %>
    
  23. Save the file.

  24. In a browser, go to: localhost:3000

    As you can see, that got rid of the default Tinfoil Hat images and added the appropriate image for the product we’ve been editing. We’ll get to displaying the images for the other products in the next exercise.

  25. Click on the product you’ve been editing to see its page. Looks like we still need to replace the default image there.

  26. In your code editor, open nutty > app > views > products > show.html.erb

  27. Around line 17, select the following code:

    <img class="product" src="/img/product_images/tinfoil-hat.jpg" alt="<%= @product.title %>">
    
  28. Replace the image tag with the embedded Ruby code shown in bold:

       <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 -->
    
  29. Save the file.

  30. In the browser, reload the product page and its image should be there!

  31. Leave the two tabs open and the server running in Terminal so we can continue with them in the next exercise.

Noble Desktop Publishing Team

The Noble Desktop Publishing Team includes writers, editors, instructors, and industry experts who collaborate to publish up-to-date content on today's top skills and software. From career guides to software tutorials to introductory video courses, Noble aims to produce relevant learning resources for people interested in coding, design, data, marketing, and other in-demand professions.

More articles by Noble Desktop Publishing Team

How to Learn Coding

Master coding with hands-on training. Learning how to code in JavaScript, Python, and other popular languages can pave the way to a job in tech, such as web development, data science & analytics, or software engineering.

Yelp Facebook LinkedIn YouTube Twitter Instagram