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:
- 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
- Administrate (Modern Alternative)
Clean, Rails-way approach by Thoughtbot
Good for custom UIs, less configuration
More work to set up initially
- Rails Admin (What you asked about)
Quick setup but limited customization
Less actively maintained
Good for simple admin needs
- 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:
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:
- Nested Forms: You can create/update a Product and its ProductVariants in a single form submission
- Mass Assignment: Allows passing nested attributes through strong parameters
- 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:
- Dashboard – Key metrics, recent activity, revenue overview
- User Management – Role management, order history
- Product Management – Full CRUD with image uploads and nested variants
- Order Management – Status updates, batch actions
- 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:
- Nested Variants: Create/edit products with multiple variants in one form
- Image Management: Upload multiple product images
- Order Processing: Admin can update order statuses with batch actions
- User Management: Promote users to admin, view order history
- 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
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:
bundle exec tailwindcss build
The Tailwind CSS is already built and located in app/assets/builds/tailwind.css. Let’s fix the configuration:
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:
- 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.
- Found the correct location: Discovered that the
tailwindcss-rails gem builds the CSS file to app/assets/builds/tailwind.css.
- 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
- Updated the layout file:
- Changed from
<%= stylesheet_link_tag "/tailwind/application.css" %>
- To the correct
<%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
- 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
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:
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:
- ✅ Removed the Font Awesome CDN link (no more external dependency)
- ✅ Added
rails_icons gem with Heroicons as the default library
- ✅ Added Font Awesome as a custom library with all variants (solid, regular, brands)
- ✅ 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:
- Information disclosure – Searching sensitive fields like passwords
- Performance issues – Searching on unindexed or inappropriate fields
- 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
- Security: Explicit control over what can be searched
- Performance: Only searchable fields need indexes
- Usability: Provides powerful admin interface features
- 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:
- All CSS files properly compiled:
- tailwind.css ✅
- application.css ✅
- active_admin.css ✅
- All JavaScript files properly compiled:
- application.js ✅
- controllers/application.js ✅
- controllers/decorative_background_controller.js ✅
- controllers/hello_controller.js ✅
- controllers/index.js ✅
- 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:
- ✅ 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
- ✅ 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
- ✅ Phase 3:
feat: Integrate ActiveAdmin for comprehensive admin interface #94
- Complete ActiveAdmin setup with authentication
- Full admin resources for all e-commerce models
- ✅ 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 🚀…