| name | rails-service-objects |
| description | Design and implement Rails service objects for complex multi-step business logic. Use when business operations span multiple models, require transaction coordination, or need complex error handling with structured results. |
Rails Service Objects Specialist
Specialized in creating clean, testable service objects for complex business workflows.
When to Use This Skill
- Implementing multi-step business processes (e.g., order processing, payment workflows)
- Coordinating operations across multiple models
- Business logic that requires transaction safety
- Complex workflows with multiple success/failure paths
- Operations that need structured result objects
Core Principles
- Single Responsibility: Each service handles one business operation
- Call Interface: Use
callmethod as the primary interface - Result Objects: Return structured success/failure results
- Transaction Safety: Wrap operations in transactions when needed
- Testability: Easy to test in isolation
Implementation Guidelines
Basic Service Object Structure
# app/services/order_processing_service.rb
class OrderProcessingService
def initialize(order, options = {})
@order = order
@options = options
end
def call
ActiveRecord::Base.transaction do
validate_order!
charge_payment
update_inventory
send_confirmation
Result.success(@order)
end
rescue => e
Result.failure(e.message)
end
private
# WHY: Ensure order meets business rules before processing
def validate_order!
raise ValidationError unless @order.valid? && @order.items.any?
end
def charge_payment
# Payment processing logic
end
def update_inventory
# Inventory update logic
end
def send_confirmation
# Email notification logic
end
end
Usage Pattern
# In controller
def create
service = OrderProcessingService.new(order, payment_method: params[:payment_method])
result = service.call
if result.success?
redirect_to order_path(result.data), notice: 'Order processed successfully'
else
redirect_to cart_path, alert: result.error
end
end
Result Object Pattern
# app/services/result.rb
class Result
attr_reader :data, :error
def self.success(data = nil)
new(success: true, data: data)
end
def self.failure(error)
new(success: false, error: error)
end
def initialize(success:, data: nil, error: nil)
@success = success
@data = data
@error = error
end
def success?
@success
end
def failure?
!@success
end
end
Tools to Use
Read: Read existing service objects and modelsWrite: Create new service object filesEdit: Modify existing service objectsBash: Run tests for service objectsmcp__serena__find_symbol: Find related models and services
Bash Commands
# Generate service directory (if needed)
mkdir -p app/services
# Run service tests
bundle exec rspec spec/services/order_processing_service_spec.rb
Workflow
- Understand Requirements: Clarify business logic requirements
- Write Tests First: Use
rails-rspec-testingskill - Verify Tests Fail: Confirm tests fail correctly
- Implement Service: Create service object with clear interface
- Handle Errors: Implement proper error handling
- Return Results: Use Result objects for structured responses
- Run Tests: Ensure all tests pass
- Run Rubocop: Validate code style
Related Skills
rails-rspec-testing: For writing service object testsrails-transactions: For transaction management within servicesrails-error-handling: For comprehensive error handlingrails-model-design: For understanding model interfaces
Coding Standards
TDD Workflow
Follow TDD Workflow
Key Reminders
- Keep services focused on single business operation
- Always return Result objects for consistent interface
- Use transactions when coordinating multiple models
- Extract complex logic into private methods
- Write tests before implementation (TDD)
- Use English comments explaining WHY