Topics Covered in This Ruby on Rails Tutorial:
Installing the FriendlyId Gem, Creating SEO-Optimized URLs with Slugs, and Rebuilding Your Product Database
Exercise Overview
In this comprehensive exercise, you'll transform your Rails application into a production-ready e-commerce platform. We'll implement proper image handling for all products, create search engine-optimized URLs that boost your site's SEO performance, and leverage Markdown for streamlined content management. These improvements will significantly enhance both user experience and search engine visibility.
If you've completed the previous exercises (8A–8B), you can skip the following sidebar and continue to the Setup section. However, if you haven't finished those foundational exercises, follow the steps below to get your development environment properly configured.
What You'll Accomplish
1Install FriendlyId Gem
Add and configure the FriendlyId gem to enable SEO-friendly URL generation
2Implement Slug System
Create unique slug fields and modify models to use human-readable URLs
3Display Product Images
Configure Active Storage to show unique images for all products
4Rebuild Database
Recreate the database with proper seeds file for images and slugs
Prerequisite Setup: If You Haven't Completed Exercises 8A–8B
- Close any open files in your code editor to start with a clean workspace.
- Open the Finder and navigate to Class Files > yourname-Rails Class
- Open Terminal to access the command line interface.
- Type
cdfollowed by a single space (do NOT press Return yet). - Drag the yourname-Rails Class folder from the Finder window directly into the Terminal window, then press ENTER to navigate to that directory.
- Run
rm -rf nuttyto completely remove your existing copy of the nutty site. - Run
git clone https://bitbucket.org/Noble Desktop/nutty.gitto download the latest version of the That Nutty Guy repository. - Type
cd nuttyto enter the newly cloned directory. - Type
git checkout 8Bto switch to the branch containing all completed work from the previous exercise. - Run
bundle installto install all required Ruby gems and dependencies. - Run
yarn install --check-filesto install all JavaScript dependencies and verify file integrity.
URL Structure: Before vs After
| Feature | Current URLs | SEO-Friendly URLs |
|---|---|---|
| Product Pages | localhost:3000/products/1 | localhost:3000/products/buddha-board |
| SEO Value | No keyword relevance | Product name in URL |
| User Experience | Generic numeric ID | Descriptive and memorable |
Google considers URL contents as one of the most important factors for determining page keywords and search relevance. Including product names in URLs directly improves SEO performance.
Setup and Initial Configuration
Before we dive into implementing SEO-friendly URLs, let's examine the current state of your application and understand why these improvements matter for modern web development.
Open your web browser and navigate to: localhost:3000
Click on any product to view its detail page.
Examine the URL structure—you'll notice it follows the pattern: localhost:3000/products/1
While these numeric URLs are functional, they're problematic for modern SEO best practices. Search engines like Google heavily weight URL content when determining page relevance and ranking. A URL like
/products/1tells search engines nothing about your product, whereas/products/organic-dark-chocolate-trufflesimmediately signals the page content and improves keyword association.The FriendlyId gem solves this problem elegantly by replacing numeric IDs with human-readable slugs derived from your content.
In your browser, navigate to: github.com/norman/friendly_id
Scroll down to the Rails Quickstart section and copy the current gem declaration (the version may be newer than shown here, which is perfectly fine—always use the latest stable version):
gem 'friendly_id', '~> 5.4.0'This declaration will be added to your application's Gemfile to manage the dependency.
Continue working with the nutty folder located in Desktop > Class Files > yourname-Rails Class > nutty
For optimal workflow, open the entire nutty folder in your code editor (VS Code, Sublime Text, or similar) to enable project-wide navigation and search capabilities.
In your code editor, open nutty > Gemfile
Scroll to the bottom of the file and add the following lines:
# Use FriendlyId for SEO-friendly URLs gem 'friendly_id', '~> 5.4.0'Save the file using Cmd+S (Mac) or Ctrl+S (Windows).
Remember: whenever you add new gems to your Rails application, you must restart the development server to load the new dependencies properly.
Switch to the ruby tab in your Terminal window (the one currently running the Rails server).
Press Ctrl+C to gracefully stop the server.
Install the new gem by running:
bundle installRestart your Rails development server:
rails serverSwitch to your second Terminal tab to continue with configuration commands.
Complete the FriendlyId setup by running these configuration commands:
rails generate friendly_id rails db:migrateThese commands create the necessary database tables and configuration files for FriendlyId to function properly.
URL Structure: Before vs After
| Feature | Current URLs | SEO-Friendly URLs |
|---|---|---|
| Product Pages | localhost:3000/products/1 | localhost:3000/products/buddha-board |
| SEO Value | No keyword relevance | Product name in URL |
| User Experience | Generic numeric ID | Descriptive and memorable |
Google considers URL contents as one of the most important factors for determining page keywords and search relevance. Including product names in URLs directly improves SEO performance.
Implementing Slugs for SEO-Optimized URLs
FriendlyId operates using slugs—URL-friendly versions of your content titles. Think of slugs as the bridge between human-readable content and web-safe URLs. Instead of /products/1, you'll have URLs like /products/buddha-board that both users and search engines can immediately understand.
First, we'll add a database field to store these slug values. In Terminal, run:
rails generate migration add_slug_to_products slug:uniqThe
uniqtype is Rails shorthand for a unique string field. Since each slug represents a unique URL, ensuring uniqueness at the database level prevents conflicts and maintains data integrity.In your code editor, locate and open nutty > db > migrate > [timestamp]_add_slug_to_products.rb
Note: The timestamp portion of the filename will be unique to when you generated this migration.
Examine the generated migration code:
add_column :products, :slug, :string add_index :products, :slug, unique: trueThis migration does two critical things: it adds the slug column and creates a unique index. The index is crucial for performance—without it, your application would slow significantly as your product catalog grows. Database lookups on indexed fields are orders of magnitude faster than unindexed searches.
Close the migration file after reviewing it.
Apply the migration to your database:
rails db:migrateNow we'll configure the Product model to use FriendlyId. Open nutty > app > models > product.rb
Add the FriendlyId configuration after the existing
has_one_attached :imageline:has_one_attached :image extend FriendlyId friendly_id :title, use: [:slugged, :finders] endThis configuration tells FriendlyId to generate slugs from the product title and to override Rails' default finder methods to work with slugs instead of numeric IDs.
Save the file.
We also need to configure Active Admin to work with FriendlyId. Open app > admin > products.rb and add this controller configuration at the bottom:
f.actions end controller do def find_resource scoped_collection.friendly.find(params[:id]) end end endNow let's test the implementation. In your browser, navigate to: localhost:3000/admin
Sign in with your admin credentials if prompted.
Click on Products in the navigation.
To generate a slug, we need to trigger an update on any product. Find the Buddha Board product (typically the first in the list).
Click on the product ID number (8) to view the product details.
Click Edit Product in the top right corner.
Without changing any information, click the Update Product button.
This triggers FriendlyId to generate a slug based on the product title.
Check the URL bar—you should now see: localhost:3000/admin/products/buddha-board
Test the public-facing URL by visiting: localhost:3000/products/buddha-board
Congratulations! You now have SEO-optimized URLs that clearly communicate page content to both users and search engines.
Database Reconstruction and Bulk Image Processing
Now that we've implemented both Active Storage and FriendlyId, let's take a professional approach to data management. Rather than manually updating each product through the admin interface—a time-consuming and error-prone process—we'll rebuild our database programmatically. This approach ensures consistency and demonstrates real-world deployment practices.
The key challenge is programmatically attaching image files to model objects. Fortunately, Rails Active Storage makes this surprisingly straightforward, whether your images are stored locally, on a CDN, or accessible via URL.
Open nutty > db > seeds.rb in your code editor.
Review the pre-configured seeds file structure. Note these key elements:
- Each product entry includes an
:imagekey with a corresponding filename (visible around lines 16, 29, 40, etc.) - The file uses an array-based structure containing product attributes and image references
- An
eachloop processes each product, creates a new Product object, and handles success/error reporting
We need to enhance this loop to handle image attachment before saving each product record.
- Each product entry includes an
Locate the product creation loop around line 114 and enhance it with image processing logic:
p = Product.new(product[:attributes]) fn = "public/img/product_images/#{product[:image]}" if File.exist?(fn) p.image.attach(io: File.open(fn), filename: product[:image]) else puts "Warning: Image file not found for #{product[:attributes][:title]}: #{fn}" end if p.save puts "Created #{p.title}" else puts "Failed to create #{product[:attributes][:title]}: #{p.errors.full_messages.join(', ')}" endThis enhanced code includes proper error handling and detailed logging—essential for production-quality applications.
Save the file.
Now we'll reset our database with the improved seed data. Open the Rails console:
rails consoleRemove all existing products:
Product.destroy_allThis ensures a clean slate for our enhanced data structure.
Exit the console and return to the command prompt:
exitPopulate your database with the new seed data:
rails db:seedWatch the output to confirm successful product creation and image attachment.
Test the results by navigating to localhost:3000 in your browser (refresh if already open).
All product images should now display correctly on both the catalog and individual product pages.
Click through several products to verify that each one displays its unique image and uses its SEO-friendly URL structure.
You've successfully implemented a professional-grade e-commerce catalog with optimized URLs and proper image management—key components of any serious web application.