Design Studio – Rails 8 e-commerce application: Integrate active admin

Now let’s create an admin interface for our e-commerce Application.

We have a well-structured e-commerce Rails application with:

Models: User, Product, ProductVariant, Order, OrderItem
Authentication: Custom session-based auth with user roles (customer/admin)
Authorization: Already has admin role checking

Admin Interface Recommendations

Here are the best options for Rails admin interfaces, ranked by suitability for our project:

  1. ActiveAdmin (Recommended ⭐)
    Best fit for e-commerce with complex associations
    Excellent filtering, search, and batch operations
    Great customization options and ecosystem
    Handles your Product → ProductVariant → OrderItem relationships well
  2. Administrate (Modern Alternative)
    Clean, Rails-way approach by Thoughtbot
    Good for custom UIs, less configuration
    More work to set up initially
  3. Rails Admin (What you asked about)
    Quick setup but limited customization
    Less actively maintained
    Good for simple admin needs
  4. Avo (Modern Premium)
    Beautiful modern UI
    Some features require paid version

    https://avohq.io/rails-admin
    https://docs.avohq.io/3.0/

Choose ActiveAdmin for our e-commerce application. Let’s integrate it with our existing authentication system

Add in Gemfile:

gem "activeadmin"
gem "sassc-rails" # Required for ActiveAdmin
gem "image_processing", "~> 1.2" # For variant processing if not already present

Bundle Install and run the Active Admin Generator:

$ bundle install
$ rails generate active_admin:install --skip-users
definition of Rules was here
create app/assets/javascripts/active_admin.js
create app/assets/stylesheets/active_admin.scss
create db/migrate/20250710083516_create_active_admin_comments.rb

Migration File created by Active Admin:

class CreateActiveAdminComments < ActiveRecord::Migration[8.0]
  def self.up
    create_table :active_admin_comments do |t|
      t.string :namespace
      t.text   :body
      t.references :resource, polymorphic: true
      t.references :author, polymorphic: true
      t.timestamps
    end
    add_index :active_admin_comments, [ :namespace ]
  end

  def self.down
    drop_table :active_admin_comments
  end
end

Run database migration:

$ rails db:migrate

in app/initializers/active_admin.rb

# This setting changes the method which Active Admin calls
  # within the application controller.
  config.authentication_method = :authenticate_admin_user!
....
# This setting changes the method which Active Admin calls
  # (within the application controller) to return the currently logged in user.
  config.current_user_method = :current_admin_user
....
 # Default:
  config.logout_link_path = :destroy_session_path

in app/controllers/application_controller.rb

private

  def authenticate_admin_user!
    require_authentication
    ensure_admin
  end

  def current_admin_user
    Current.user if Current.user&.admin?
  end

Run the active admin user, product generator:

rails generate active_admin:resource User
rails generate active_admin:resource Product
rails generate active_admin:resource ProductVariant
rails generate active_admin:resource Order
rails generate active_admin:resource OrderItem

Let’s update all the active admin resources with fields, filters, attributes, panels etc.

Let’s add accepts_nested_attributes_for :variants, allow_destroy: true in Product Model.

accepts_nested_attributes_for is a Rails feature that allows a parent model to accept and process attributes for its associated child models through nested parameters. Here’s what it does:

What it enables:

  1. Nested Forms: You can create/update a Product and its ProductVariants in a single form submission
  2. Mass Assignment: Allows passing nested attributes through strong parameters
  3. CRUD Operations: Create, update, and delete associated records through the parent

In our Product model

class Product < ApplicationRecord
  has_many :variants, dependent: :destroy, class_name: "ProductVariant"
  accepts_nested_attributes_for :variants, allow_destroy: true
end

What this allows:

Before: You’d need separate forms/requests for Product and ProductVariant

# Create product first
product = Product.create(name: "T-Shirt", brand: "Nike")

# Then create variants separately
product.variants.create(size: "M", color: "Red", sku: "NIKE-001-M-RED")
product.variants.create(size: "L", color: "Blue", sku: "NIKE-001-L-BLUE")

After: You can do it all in one go:

Product.create(
  name: "T-Shirt",
  brand: "Nike",
  variants_attributes: [
    { size: "M", color: "Red", sku: "NIKE-001-M-RED" },
    { size: "L", color: "Blue", sku: "NIKE-001-L-BLUE" }
  ]
)

In ActiveAdmin context:

This enables the nested form I created in app/admin/products.rb:

f.inputs "Product Variants" do
  f.has_many :variants, allow_destroy: true, new_record: true do |v|
    v.input :size
    v.input :color
    v.input :sku
    # ... other variant fields
  end
end
The allow_destroy: true option:
  • Allows deleting associated records by passing _destroy: ‘1’
  • Essential for updating existing products with variants
Strong Parameters:

In the controller, you need to permit the nested attributes:

permit_params :name, :brand, :category, 
              variants_attributes: [:id, :size, :color, :sku, :mrp, :discount_percent, :_destroy]

Propshaft vs Sprockets

We have an error after integrating ActiveAdmin:

 Rendered layout layouts/application.html.erb (Duration: 13.9ms | GC: 0.5ms)
Completed 500 Internal Server Error in 118ms (ActiveRecord: 28.7ms (1 query, 0 cached) | GC: 27.0ms)

ActionView::Template::Error (undefined method 'load_path' for an instance of Sprockets::Environment)
Caused by: NoMethodError (undefined method 'load_path' for an instance of Sprockets::Environment)

Information for: ActionView::Template::Error (undefined method 'load_path' for an instance of Sprockets::Environment):
    14:     <link rel="icon" href="/icon.svg" type="image/svg+xml">
    15:     <link rel="apple-touch-icon" href="/icon.png">

This error occurs because Rails 8 uses Propshaft by default, but ActiveAdmin requires Sprockets. There’s a conflict between the two asset pipelines. Let’s fix this by switching to Sprockets completely:

Add in Gemfile:

# Use Sprockets for asset pipeline (required for ActiveAdmin)
gem "sprockets-rails"

$ bundle install

# application.rb

# Use Sprockets for asset pipeline
config.assets.enabled = true

Let’s create an admin user for testing our ActiveAdmin:

# seed.rb
# Create admin user
admin_user = User.find_or_create_by(email: "admin@designstudio.com") do |user|
  user.password = "password123"
  user.role = "admin"
end

puts "Admin user created: #{admin_user.email}" if admin_user.persisted?

# run seed
✗ rails db:seed

✅ We have Successfully Integrated ActiveAdmin with Nested Attributes!

I’ve successfully converted your Rails application to use nested attributes (variants_attributes) across the entire stack and integrated ActiveAdmin as your admin interface. Here’s what I accomplished:

🔧 What I Fixed & Updated:

1. Asset Pipeline Issue:

  • Switched from Propshaft to Sprockets (required for ActiveAdmin)
  • Updated Gemfile and application configuration
  • Fixed the load_path error you encountered

2. Model Changes:

  • Added accepts_nested_attributes_for :variants, allow_destroy: true to Product model

3. Controller Updates:

  • Changed from singular product_variant to plural variants_attributes
  • Simplified create/update actions to use Rails nested attributes handling
  • Updated strong parameters to permit nested variant attributes

4. View Improvements:

  • Updated product form to handle multiple variants with JavaScript
  • Added “Add Another Variant” functionality
  • Implemented proper nested form fields for all variant attributes

5. ActiveAdmin Configuration:

  • Set up authentication using your existing user system
  • Created comprehensive admin resources for all models
  • Added nested variant management in product forms
  • Built an informative dashboard with key metrics

🎯 Admin Features You Now Have:

  1. Dashboard – Key metrics, recent activity, revenue overview
  2. User Management – Role management, order history
  3. Product Management – Full CRUD with image uploads and nested variants
  4. Order Management – Status updates, batch actions
  5. Inventory Management – ProductVariant and OrderItem tracking

🔑 Admin Access:

  • URL: http://localhost:3000/admin
  • Email: admin@designstudio.com
  • Password: password123

📊 Comparison vs Rails Admin:

ActiveAdmin Advantages:

  • ✅ Better for complex e-commerce relationships
  • ✅ Excellent filtering and search capabilities
  • ✅ Powerful batch operations
  • ✅ Highly customizable forms and views
  • ✅ Active development and community

Rails Admin:

  • ❌ Less actively maintained
  • ❌ Limited customization options
  • ❌ Not as suitable for complex nested relationships

🚀 What’s Working Now:

  1. Nested Variants: Create/edit products with multiple variants in one form
  2. Image Management: Upload multiple product images
  3. Order Processing: Admin can update order statuses with batch actions
  4. User Management: Promote users to admin, view order history
  5. Dashboard Analytics: Revenue tracking, popular products, recent activity

Visit /admin to explore your new admin interface, Cheers!

Check docs: https://activeadmin.info/0-installation.html

⚠️ Tailwind UI Issue after moving to Sprockets

The issue is with <%= stylesheet_link_tag "/tailwind/application.css", "data-turbo-track": "reload" %> where we are trying to load Tailwind CSS from an incorrect path. The tailwindcss-rails gem serves Tailwind CSS differently. Let me fix this:

ls -la app/assets/tailwind/
curl -I http://localhost:3000/tailwind/application.css
rails routes | grep -i tailwind

The issue is that the /tailwind/application.css path is returning 404. The tailwindcss-rails gem works differently. Let’s check how it’s configured and fix this:

find . -name "*.css" -path "*/public/*" | head -10
rails assets:precompile

Now let’s test if the Tailwind CSS is properly accessible:

curl -I http://localhost:3000/assets/tailwind/application.css

The issue is that with the tailwindcss-rails gem, Tailwind CSS gets compiled into the main application.css file rather than a separate file. Let’s check the current asset manifest and fix the layout:

rails assets:precompile
bundle exec tailwindcss build

The Tailwind CSS is already built and located in app/assets/builds/tailwind.css. Let’s fix the configuration:

rails assets:precompile
curl -I http://localhost:3000/assets/tailwind.css

The issue has been fixed. The Tailwind CSS is now properly accessible. Here’s what I did to resolve the problem:

  1. Identified the issue: The Tailwind CSS was being incorrectly referenced as /tailwind/application.css in the layout file, but it wasn’t being served properly through the asset pipeline.
  2. Found the correct location: Discovered that the tailwindcss-rails gem builds the CSS file to app/assets/builds/tailwind.css.
  3. Fixed the asset pipeline configuration:
  • Updated app/assets/config/manifest.js to include //= link_tree ../builds which includes the built Tailwind CSS
  • Removed the incorrect tailwind/application.css reference
  1. Updated the layout file:
  • Changed from <%= stylesheet_link_tag "/tailwind/application.css" %>
  • To the correct <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
  1. Verified the fix:
  • Successfully precompiled assets
  • Confirmed that http://localhost:3000/assets/tailwind.css returns a 200 OK status

Install Rails Icons 🍁

For better font-awesome assets, lets add rails-icons gem:

# Rails Icons - Modern icon library support
gem "rails_icons"

$ rails generate rails_icons:install --help
$ rails generate rails_icons:install --libraries=heroicons

$ npm install @fortawesome/fontawesome-free

How to migrate from the CDN to Rails Icons

For a production Rails application, it’s generally better to use a gem rather than a CDN for Font Awesome. Here’s why:

CDN Issues:

  • External dependency (can fail if CDN is down)
  • Privacy concerns (external requests)
  • No version control
  • Requires internet connection
  • Not cacheable with your assets

Gem Benefits:

  • Self-hosted (no external dependencies)
  • Better performance (served with your assets)
  • Version control
  • Works offline
  • Follows Rails conventions
  • Better for production

Based on my research, adding a gem is definitely the better approach for a production Rails application. Here are the best options:

Option 1: Modern approach with npm package (Recommended)

Since we’re using Rails 8 with modern tooling, I’d recommend using the npm package:

yarn add @fortawesome/fontawesome-free
npm --version
which node

However, given your current setup, I’d recommend Option 2 which is more Rails-native:

Option 2: Rails Icons gem (Recommended for our setup)

This is a modern gem that supports Font Awesome and other icon libraries with a clean Rails API:

bundle install
rails generate rails_icons:install --help
rails generate rails_icons:install --libraries=heroicons

Let’s remove the CDN and set up Rails Icons properly. Since we’re already using Font Awesome extensively, let’s add Font Awesome as a custom library:

rails generate rails_icons:initializer --custom=fontawesome
npm install @fortawesome/fontawesome-free
find node_modules/@fortawesome/fontawesome-free -name "*.svg" -type f | head -5
cp -r node_modules/@fortawesome/fontawesome-free/svgs/* app/assets/svg/icons/fontawesome/

Rails Icons is now properly set up instead of the CDN. Here’s what we’ve accomplished:

What’s Changed:

  1. Removed the Font Awesome CDN link (no more external dependency)
  2. Added rails_icons gem with Heroicons as the default library
  3. Added Font Awesome as a custom library with all variants (solid, regular, brands)
  4. Self-hosted all icons through Rails asset pipeline

What is Ransack?

Ransack is a popular Ruby gem that provides powerful search and filtering capabilities for Rails applications. It’s commonly used with ActiveAdmin (which your app uses) to create searchable, filterable, and sortable data tables.

Ransackable Attributes and Associations

ransackable_attributes

This method defines which model attributes can be searched, filtered, or sorted through Ransack. It’s a security feature that prevents unauthorized access to sensitive data.

def self.ransackable_attributes(auth_object = nil)
  %w[id email role created_at updated_at password_reset_token password_reset_sent_at]
end

What it does:

  • Allows searching/filtering by id, email, role, created_at, updated_at, etc.
  • Prevents searching by sensitive fields like password_digest
  • The auth_object parameter can be used for role-based access control

ransackable_associations

This method defines which model associations can be used in Ransack queries.

def self.ransackable_associations(auth_object = nil)
  %w[orders sessions]
end

What it does:

  • Allows searching/filtering by related models (e.g., “users who have orders”)
  • Enables joins and complex queries across associations

Why This Matters for Security

Without these methods, Rails 7+ will raise warnings or errors because Ransack needs explicit permission to search certain fields. This prevents:

  1. Information disclosure – Searching sensitive fields like passwords
  2. Performance issues – Searching on unindexed or inappropriate fields
  3. Unauthorized access – Accessing data through unexpected query parameters

Example Usage in ActiveAdmin

In your ActiveAdmin dashboard, this enables features like:

# In app/admin/users.rb
ActiveAdmin.register User do
  # Users can now search by email, role, etc.
  # Users can filter by orders, sessions
  # Users can sort by created_at, updated_at
end

In Our User Model

Looking at your User model:

def self.ransackable_attributes(auth_object = nil)
  %w[id email role created_at updated_at password_reset_token password_reset_sent_at]
end

def self.ransackable_associations(auth_object = nil)
  %w[orders sessions]
end

This means:

  • ✅ Admins can search users by email, role, creation date
  • ✅ Admins can filter users by their orders or sessions
  • ✅ Admins can sort users by any of these attributes
  • ❌ Admins cannot search by password_digest (secure)
  • ❌ Admins cannot search by other sensitive fields

Benefits

  1. Security: Explicit control over what can be searched
  2. Performance: Only searchable fields need indexes
  3. Usability: Provides powerful admin interface features
  4. Compliance: Helps meet data protection requirements

Migration Guide:

Old CDN way:

<i class="fas fa-user"></i>          <!-- solid -->
<i class="far fa-star"></i>          <!-- regular -->
<i class="fab fa-facebook-f"></i>    <!-- brands -->

New Rails Icons way:

<%= icon "user", library: "fontawesome", variant: "solid", class: "size-6" %>
<%= icon "star", library: "fontawesome", variant: "regular", class: "size-6" %>
<%= icon "facebook-f", library: "fontawesome", variant: "brands", class: "size-6" %>

Or use modern Heroicons (recommended for new icons):

<%= icon "user", class: "size-6" %>
<%= icon "star", class: "size-6" %>
<%= icon "heart", class: "size-6" %>

Benefits:

  • No external dependencies (works offline)
  • Better performance (served with your assets)
  • Version control over icons
  • Multiple libraries (Font Awesome + Heroicons + more)
  • Consistent API across all icon libraries
  • Better for production and privacy

Our application should work exactly the same now, but with better performance and no external dependencies! You can gradually migrate icons from <i class="fas fa-x"> to <%= icon "x", library: "fontawesome", variant: "solid" %> as needed.

Asset Issue Again

✅ Final Fix Applied:

Added //= link_tree ../../javascript .js to the manifest, which tells Sprockets to include all JavaScript files from the app/javascript directory tree.

✅ What’s Working Now:

  1. All CSS files properly compiled:
  • tailwind.css ✅
  • application.css ✅
  • active_admin.css ✅
  1. All JavaScript files properly compiled:
  • application.js ✅
  • controllers/application.js ✅
  • controllers/decorative_background_controller.js ✅
  • controllers/hello_controller.js ✅
  • controllers/index.js ✅
  1. Asset Pipeline fully functional:
  • Sprockets serving all assets correctly
  • Proper cache headers and ETags
  • All asset links declared in manifest

🎯 Current Status:

Our Rails application now has:

  • ✅ Modern asset pipeline with Sprockets + Importmap
  • ✅ Tailwind CSS for styling (self-hosted)
  • ✅ ActiveAdmin for administration
  • ✅ Rails Icons instead of Font Awesome CDN
  • ✅ Stimulus controllers for JavaScript functionality
  • ✅ All assets properly precompiled and served

Check Github: Active admin changes

📋 Clean Commit History Summary:

  1. ✅ Phase 1: feat: Add Rails Icons gem with Font Awesome and Heroicons support #94
  • Replaced Font Awesome CDN with self-hosted icons
  • Added Rails Icons with unified API for multiple icon libraries
  1. ✅ Phase 2: task: Migrate from Propshaft to Sprockets asset pipeline #96
  • Switched from Propshaft to Sprockets for ActiveAdmin compatibility
  • Fixed asset compilation and linking issues
  1. ✅ Phase 3: feat: Integrate ActiveAdmin for comprehensive admin interface #94
  • Complete ActiveAdmin setup with authentication
  • Full admin resources for all e-commerce models
  1. ✅ Phase 4: fix: Resolve ActiveAdmin PostgreSQL and Ransack security issues #94
  • Fixed PostgreSQL GROUP BY errors in dashboard
  • Added Ransack security configuration for all models

🚀 Our ActiveAdmin is now fully functional!

You should now be able to:

  • ✅ Access the admin dashboard at localhost:3000/admin
  • ✅ View analytics and statistics without GROUP BY errors
  • ✅ Search and filter all resources safely with Ransack
  • ✅ Manage Users, Products, Variants, Orders, and Order Items
  • ✅ Use nested attributes for product variants
  • ✅ Perform batch operations and advanced filtering

Test it out: Visit localhost:3000/admin and log in with your admin credentials to see the beautiful, fully-functional admin interface! 🎯

to be continued 🚀…

Unknown's avatar

Author: Abhilash

Hi, I’m Abhilash! A seasoned web developer with 15 years of experience specializing in Ruby and Ruby on Rails. Since 2010, I’ve built scalable, robust web applications and worked with frameworks like Angular, Sinatra, Laravel, Node.js, Vue and React. Passionate about clean, maintainable code and continuous learning, I share insights, tutorials, and experiences here. Let’s explore the ever-evolving world of web development together!

Leave a comment