Topics Covered in This Ruby on Rails Tutorial:
Adding an Image to the Cookbook, Introducing PostgreSQL
Exercise Overview
After covering the fundamentals across fourteen comprehensive sections, we've built a solid foundation in Rails development. However, everything we've accomplished has remained confined to our local development environment. It's time to prepare your applications for the real world—where they'll face actual traffic, user interactions, and production challenges.
This section bridges the gap between development and deployment by enhancing our cookbook application with production-ready features. We'll leverage Active Storage to implement image uploads—a critical feature in modern web applications—and configure AWS S3 for scalable media storage.
Additionally, we'll transition from SQLite to PostgreSQL, the industry-standard database that powers countless production Rails applications. This shift isn't just about compatibility; it's about understanding the architectural decisions that separate hobby projects from professional applications.
Deployment Preparation Process
Add Image Support
Integrate Active Storage with image processing capabilities to handle file uploads for recipe images
Install PostgreSQL
Replace SQLite with PostgreSQL database system for production-level performance and reliability
Configure Database
Set up PostgreSQL user roles, permissions, and Rails database configuration
Adding an Image to the Cookbook
Visual content drives user engagement, and recipe applications particularly benefit from appetizing imagery. Let's implement a robust image upload system using Rails' Active Storage framework.
Navigate back to your cookbook application directory and open it in your preferred code editor. Ensure you have both your editor and Terminal positioned for efficient workflow.
Launch Terminal in your cookbook directory. This dual-window setup should feel natural by now—it's the standard workflow for professional Rails development.
Open your Gemfile and locate line 26. Uncomment the image processing gem, which provides the ImageMagick bindings necessary for image manipulation:
gem 'image_processing', '~> 1.2'Save the file to commit your changes.
Return to Terminal and install the new dependency:
bundleInitialize Active Storage, Rails' built-in solution for handling file uploads. Execute these commands to generate the necessary database tables and run the migration:
rails active_storage:install rails db:migrateModify your Recipe model to establish the attachment relationship. This single line enables your recipes to store associated images:
class Recipe < ApplicationRecord has_one_attached :image endStart your Rails server in a separate Terminal window to test changes in real-time:
rails sUpdate the form partial at
app > views > recipes > _form.html.erbto include a file upload field. This addition seamlessly integrates with Rails' form helpers:<%= form.text_area :directions %> </div> <div class="field"> <%= form.label :image %> <%= form.file_field :image %> </div> <div class="actions"> <%= form.submit %>Configure the recipes controller at app > controllers > recipes_controller.rb to accept image uploads through strong parameters:
def recipe_params params.require(:recipe).permit(:title, :description, :prep_time, :ingredients, :directions, :image) endEnhance the recipe detail view at app > views > recipes > show.html.erb to display uploaded images. The conditional check prevents errors when no image is attached:
<%= @recipe.title %> </h1> <% if @recipe.image.attached? %> <p> <%= image_tag(@recipe.image.variant(resize: "400x400")) if @recipe.image.attached? %> </p> <% end %> <p> <em><%= @recipe.description %></em>Add thumbnail images to your index page for improved visual hierarchy. Modify app > views > recipes > index.html.erb:
<thead> <tr> <th>Image</th> <th>Title</th> <th>Prep time</th><% @recipes.each do |recipe| %> <tr> <td><%= image_tag(recipe.image.variant(resize: "100x100")) if recipe.image.attached? %></td> <td><%= recipe.title %></td>Test your implementation by navigating to http://localhost:3000. Edit an existing recipe, upload the pasta.jpg image from your snippets directory, and observe the results. You've successfully implemented a professional-grade image upload system.
Active Storage Implementation Checklist
Required for image resizing and variant processing
Creates necessary database tables for file attachments
Establishes the relationship between recipes and image files
Enables file upload functionality in the user interface
Shows resized images on both show and index pages
Image Processing Features
Variant Resizing
Images are automatically resized to 400x400 pixels on detail pages and 100x100 pixels on index pages for optimal performance and consistent display.
Conditional Display
Images only render when attached, preventing broken image links and maintaining clean layouts when no image is present.
Introducing PostgreSQL
While SQLite serves development needs admirably, production applications demand more robust database solutions. SQLite's file-based architecture, though convenient for prototyping, buckles under concurrent user loads and lacks the advanced features required for scalable applications.
Professional Rails applications typically employ dedicated database servers capable of handling complex queries, concurrent connections, and high-availability requirements. Popular enterprise options include:
- MySQL
- MariaDB
- Microsoft SQL Server
PostgreSQL stands out as the preferred choice for Rails applications, particularly in cloud deployment scenarios. Its open-source nature, exceptional performance characteristics, and comprehensive feature set make it the default database for platforms like Heroku. As we prepare for cloud deployment, PostgreSQL proficiency becomes essential.
SQLite vs PostgreSQL for Production
| Feature | SQLite | PostgreSQL |
|---|---|---|
| Traffic Handling | Limited (Lite) | High Volume |
| Setup Complexity | Simple | Moderate |
| Production Ready | No | Yes |
| Heroku Support | Not Allowed | Required |
Popular Database Options for Rails
PostgreSQL
Open source database with excellent Rails integration. Required for Heroku deployment and offers robust performance under heavy traffic loads.
MySQL
Widely used open source database with strong community support. Good alternative to PostgreSQL with similar performance characteristics.
Microsoft SQL Server
Enterprise-grade database solution with comprehensive features. Well-suited for organizations already invested in Microsoft ecosystem.
Installing PostgreSQL
Setting up PostgreSQL locally ensures development-production parity and enables seamless database synchronization between environments. This configuration is crucial for debugging production issues and maintaining data consistency.
Install PostgreSQL on your local machine using Homebrew (macOS users). This local instance will mirror your production database environment:
brew install postgresqlStart PostgreSQL and configure it to launch automatically on system startup. This ensures your development environment remains consistent:
pg_ctl -D /usr/local/var/postgresql start && brew services start postgresqlVerify successful installation by looking for this confirmation message:
==> Successfully started `postgresql` (label: homebrew.mxcl.postgresql)Unlike SQLite's zero-configuration approach, PostgreSQL requires user management and database creation. Access the PostgreSQL console to begin setup:
psql postgresYou'll see the PostgreSQL command prompt, indicating successful connection:
psql (11.4) Type "help" for help. postgres=#This interactive console accepts SQL commands and PostgreSQL-specific administrative functions.
Examine existing database users with the
\ducommand, which lists all roles (PostgreSQL's term for user accounts):postgres=# \du List of roles Role name | Attributes | Member of—————-+——————————————————————————————+—————- matt | Superuser, Create role, Create DB, Replication, Bypass RLS | {}Create a dedicated role for your Rails application following the principle of least privilege. This approach enhances security by limiting database access:
CREATE ROLE cookbook WITH LOGIN PASSWORD 'booksRcooked';Replace cookbook and booksRcooked with more secure credentials appropriate for your project. In production, use environment variables for credential management.
Grant database creation privileges to your new role. Rails requires this capability for running migrations and managing database schema:
ALTER ROLE cookbook CREATEDB;Run
\duagain to confirm the privilege assignment.Exit the superuser session and reconnect as your application user:
\qReconnect to PostgreSQL using your application credentials:
psql postgres -U cookbookCreate your application database using standard SQL syntax:
CREATE DATABASE cookbook;Verify database creation with the
\listcommand:postgres=> \list List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges—————-+—————+—————+————-+———-+—————————- cookbook | cookbook | UTF8 | C | C | postgres | matt | UTF8 | C | C | template0 | matt | UTF8 | C | C | =c/matt + | | | | | matt=CTc/matt template1 | matt | UTF8 | C | C | =c/matt + | | | | | matt=CTc/matt (4 rows)Your cookbook database now exists and is ready for Rails integration.
Exit the PostgreSQL console and return to Rails configuration:
\qAdd the PostgreSQL adapter gem to your Gemfile. This gem provides the interface between Rails and PostgreSQL:
gem 'pg'Remove SQLite3 from your Gemfile to ensure Heroku compatibility. Cloud platforms reject applications containing SQLite dependencies. Delete these lines completely:
# Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4'Install the updated dependencies:
bundleConfigure Rails to use PostgreSQL by updating config > database.yml. This file defines database connections for different environments:
default: &default adapter: postgresql encoding: unicode pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: default database: cookbook username: cookbook password: booksRcooked host: localhostExecute your existing migrations against the new PostgreSQL database:
rails db:migrateYou should observe both CreateRecipes and CreateActiveStorageTables migrations executing successfully.
Visit http://localhost:3000 to confirm your application functions correctly. The database transition will have cleared existing data—this is expected behavior when switching database systems. You're now running a production-ready database configuration locally.
PostgreSQL Installation and Setup
Install via Homebrew
Use 'brew install postgresql' to install PostgreSQL on Mac systems with automatic dependency management
Start Service
Start PostgreSQL and configure automatic startup with 'pg_ctl start && brew services start postgresql'
Create Application User
Create dedicated Rails application user with 'CREATE ROLE cookbook WITH LOGIN PASSWORD' for security isolation
Grant Database Permissions
Add CREATEDB privilege with 'ALTER ROLE cookbook CREATEDB' to enable Rails database operations
Configure Rails
Update Gemfile and database.yml configuration to use PostgreSQL adapter with connection credentials
The sqlite3 gem must be completely removed from the Gemfile, not just commented out, as Heroku will reject deployments containing SQLite dependencies.
Essential PostgreSQL Commands
Master these PostgreSQL console commands for efficient database management:
\list—List all databases in the PostgreSQL instance.\c [databasename]—Switch active database connection.\dt—List tables for the currently active database.\d [tablename]—Display detailed schema information for a specific table.\du—List all database users and their assigned roles.\q—Exit the psql console and return to the system terminal.