Organising Code with Slices
In the previous tutorial, we explored persistence with ROM in Hanami. Now we’ll dive into Slices—one of Hanami 2’s most powerful features for organizing code in larger applications.
What are Slices?
Slices are Hanami’s solution for code organization in medium-to-large applications. They provide modular boundaries that group related components together—actions, views, repositories, entities, and services—all working within a specific domain.
Think of slices as mini-applications within your main Hanami app. Each slice:
- Has its own set of actions
- Can have its own views and templates
- Contains domain-specific logic
- Shares core infrastructure with other slices
Why Use Slices?
As your application grows, dumping everything into the app/ directory becomes unmanageable. Slices solve this by:
- Domain boundaries — Group code by feature or domain
- Isolation — Each slice can be relatively independent
- Team scalability — Different teams can work on different slices
- Clear dependencies — Explicit about what each slice needs
Creating a Slice
Generate a new slice using the Hanami CLI:
bundle exec hanami generate slice admin
This creates the following structure:
app/
├── slices/
│ └── admin/
│ ├── actions/
│ ├── views/
│ └── slice.rb
The slice file defines the slice’s configuration:
# app/slices/admin.rb
module Admin
class Slice < Hanami::Slice
config.relations = {
layout: :admin
}
end
end
Anatomy of a Slice
A slice consists of several components:
Actions
Actions within a slice live in the slice’s namespace:
# app/slices/admin/actions/dashboard.rb
module Admin
module Actions
class Dashboard < Hanami::Action
def handle(request, response)
response.render "admin/dashboard", stats: compute_stats
end
private
def compute_stats
{ users: UserRepository.new.count }
end
end
end
end
Routes for slice actions are defined in config/routes.rb:
# config/routes.rb
Hanami.configure do
slice :admin, at: "/admin" do
get "/dashboard", to: "dashboard"
end
end
Views and Templates
Slice views follow the same pattern as regular views:
# app/slices/admin/views/dashboard.rb
module Admin
module Views
class Dashboard < View
def render
html "admin/dashboard", stats: stats
end
end
end
end
Repositories and Entities
Slices can have their own repositories and entities:
# app/slices/admin/repositories/user_repository.rb
module Admin
module Repositories
class UserRepository < ROM::Repository[:users]
end
end
end
Sharing Code Between Slices
Slices can explicitly import shared code from the main app or other slices:
# app/slices/admin.rb
module Admin
class Slice < Hanami::Slice
# Import from main app
import for: :users
# Import from another slice
slice :billing, import: :invoices
end
end
You can also import specific components:
# app/slices/admin.rb
module Admin
class Slice < Hanami::Slice
# Only import specific repositories
import Repositories::UserRepository, from: :users
import Entities::User, from: :users
end
end
Slice Configuration
Configure slices with their own settings:
# app/slices/admin.rb
module Admin
class Slice < Hanami::Slice
config.relations = {
layout: :admin,
assets: {
prefix: "admin-assets"
}
}
# Slice-specific middleware
middleware.use Admin::AuthMiddleware
# Slice-specific services
register Admin::Services::UserService
end
end
Practical Example: An Admin Slice
Here’s how a real admin slice might look:
# app/slices/admin/actions/users.rb
module Admin
module Actions
module Users
class Index < Hanami::Action
def handle(request, response)
users = user_repo.all
response.render "admin/users/index", users: users
end
private
def user_repo
Admin::Repositories::UserRepository.new
end
end
class Create < Hanami::Action
def handle(request, response)
user = user_repo.create(request.params[:user])
response.redirect_to "/admin/users/#{user.id}"
end
private
def user_repo
Admin::Repositories::UserRepository.new
end
end
end
end
end
When to Use Slices
Slices are ideal when:
- Building multi-tenant applications
- Creating an admin panel separate from the main app
- Implementing distinct features with their own domain logic
- Scaling teams across different features
- Building APIs for different clients (web, mobile, third-party)
Consider simpler organization if:
- Your app is small (< 10 models)
- Features are tightly coupled
- You’re prototyping
Summary
You’ve learned how Hanami Slices help organize code in larger applications:
- Slices provide modular boundaries for grouping domain-specific code
- Each slice contains actions, views, repositories, and entities
- Explicit imports control dependencies between slices
- Slice configuration allows customization per slice
Slices are the key to building maintainable Hanami applications as they grow. Combined with actions, views, and ROM persistence, you now have all the tools needed to build complete Hanami applications.