Controller Module
The Controller module is your gateway to handling HTTP requests in Plutonium applications. It combines Rails' ActionController with Plutonium-specific enhancements to create a powerful, convention-over-configuration approach that eliminates boilerplate while providing enterprise-grade features like authorization and multi-tenancy.
Module Organization
Controller functionality is distributed across multiple focused modules:
lib/plutonium/core/controller.rb
- Foundation and core utilitieslib/plutonium/resource/controller.rb
- Complete CRUD operationslib/plutonium/portal/controller.rb
- Portal-specific features and multi-tenancy
Core Philosophy
Plutonium's controller system is built on three fundamental principles:
- Convention over Configuration: Intelligent defaults that work out of the box with minimal setup
- Modular Architecture: Mix and match functionality based on your needs
- Enterprise Readiness: Built-in authentication, authorization and multi-tenancy
Understanding Resource Registration
Before diving into controllers, it's crucial to understand how Plutonium connects your resources to the web through registration and routing.
Registering Resources
Resources must be registered with each portal to become accessible through the web interface:
# packages/admin_portal/config/routes.rb
AdminPortal::Engine.routes.draw do
root to: "dashboard#index"
# Basic resource registration
register_resource User
register_resource Post
register_resource Comment
# Advanced registration with options
register_resource Profile, singular: true # Creates singular routes
register_resource Report do
# Add custom routes alongside the standard ones
member do
get :download
post :regenerate
end
end
end
What Registration Gives You
When you register a resource, Plutonium automatically creates:
- Complete CRUD routes: All standard RESTful endpoints
- Nested association routes: Based on your model's
has_many
relationships - Interactive action routes: For custom business operations
- Entity-scoped routes: If your portal uses multi-tenancy
# This simple registration:
register_resource Post
# Automatically generates:
# GET /posts # index - list all posts
# GET /posts/new # new - form for creating posts
# POST /posts # create - handle post creation
# GET /posts/:id # show - display a specific post
# GET /posts/:id/edit # edit - form for editing posts
# PATCH /posts/:id # update - handle post updates
# DELETE /posts/:id # destroy - delete posts
# Plus interactive action routes:
# GET /posts/resource_actions/:interactive_action # Resource-level actions
# POST /posts/resource_actions/:interactive_action
# GET /posts/:id/record_actions/:interactive_action # Individual record actions
# POST /posts/:id/record_actions/:interactive_action
# Plus nested routes for associations (if Post has_many :comments):
# GET /posts/:post_id/nested_comments
Entity Scoping in Routes
If your portal is scoped to an entity (like Organization), all routes are automatically nested:
# Engine configuration
class AdminPortal::Engine < Rails::Engine
include Plutonium::Portal::Engine
scope_to_entity Organization, strategy: :path
end
# Your routes become:
# GET /:organization_id/posts
# GET /:organization_id/posts/:id
# All data is automatically scoped to the organization
Controller Components
Base Controller: The Foundation
Every Plutonium controller starts with Plutonium::Core::Controller
, which provides essential framework integration:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include Plutonium::Core::Controller
# You now have access to all Plutonium controller features
end
Key Capabilities:
- Smart URL Generation: Automatic resource URL creation with proper routing
- Enhanced Flash Messages: Extended message types (
:success
,:warning
,:error
) - View Integration: Automatic view path resolution and layout management
- Resource Management: Access to registered resources and metadata
Essential Methods:
# URL generation that understands your resource structure
resource_url_for(@user) # => "/users/1"
resource_url_for(@user, action: :edit) # => "/users/1/edit"
resource_url_for(User) # => "/users"
# Build complex URL arguments for nested resources
resource_url_args_for(@user, Post) # => {controller: "/users/posts", user_id: 1}
# Access application metadata
registered_resources # => [User, Post, Comment, ...]
# Page title management
set_page_title("User Profile")
make_page_title("Dashboard") # => "Dashboard | MyApp"
Resource Controller: Complete CRUD Operations
The Resource Controller provides full CRUD functionality with zero configuration:
class PostsController < ApplicationController
include Plutonium::Resource::Controller
# That's it! All CRUD actions are automatically available:
# index, show, new, create, edit, update, destroy
end
What You Get Automatically:
- Complete CRUD Operations: All RESTful actions implemented
- Smart Parameter Handling: Automatic parameter processing and validation
- Authorization Integration: Policy checks on every action
- Query Integration: Automatic filtering, searching, and sorting
- Interaction Support: Business logic through interaction classes
- Nested Resource Support: Handles parent-child relationships automatically
- Pagination: Built-in pagination with sensible defaults
Key Methods Available:
# Resource management
resource_class # => Post
resource_record! # => @post (raises if not found)
resource_record? # => @post or nil
current_parent # => parent record for nested routes
# Parameter handling with automatic authorization
resource_params # => processed params with proper scoping
submitted_resource_params # => raw submitted parameters
# View builders for consistent UI
build_form # => form builder for the resource
build_detail # => detail view builder
build_collection # => collection view builder
# Query objects for data access
current_query_object # => handles filtering, searching, sorting
Portal Controller: Multi-Tenancy and Segmentation
Portal Controllers provide specialized functionality for multi-tenant applications and user segmentation:
module AdminPortal
class PostsController < ResourceController
include AdminPortal::Concerns::Controller
# Automatically inherits from ::PostsController
# Includes portal-specific concerns and scoping
end
end
Controller Concerns: Modular Functionality
Plutonium's controller system uses several modular concerns that provide specific capabilities:
Bootable: Initialization and Setup
Handles the foundational setup that makes everything work smoothly:
# Automatically included - provides:
# ✓ Package detection and engine resolution
# ✓ View path configuration for proper template loading
# ✓ Flash message type registration
# Available methods:
current_package # => current package module (e.g., AdminPortal)
current_engine # => current Rails engine instance
Entity Scoping: Multi-Tenancy Made Simple
Provides powerful multi-tenancy capabilities with automatic data scoping:
# Check if the controller is scoped to an entity
scoped_to_entity? # => true/false
# Get the current scoped entity
current_scoped_entity # => current organization/tenant
# Access scoping configuration
scoped_entity_strategy # => :path, :subdomain, :custom_method
scoped_entity_param_key # => :organization_id
scoped_entity_class # => Organization
Setting Up Entity Scoping
Configure scoping at the engine level and implement custom strategies as needed:
# 1. Configure in your engine
class AdminPortal::Engine < Rails::Engine
include Plutonium::Portal::Engine
# Path-based scoping (URLs like /organizations/123/posts)
scope_to_entity Organization, strategy: :path
# Or custom strategy for more control
scope_to_entity Organization, strategy: :current_organization
end
# 2. For custom strategies, implement the method in your controller concern
module AdminPortal::Concerns::Controller
private
# Method name MUST match the strategy name exactly
def current_organization
# Custom logic - could be subdomain, session, JWT, etc.
@current_organization ||= begin
# Primary: subdomain lookup
Organization.find_by(subdomain: request.subdomain) ||
# Fallback: session-based lookup
current_user.organizations.find(session[:org_id])
end
end
end
Authorizable: Comprehensive Security
Integrates with ActionPolicy to provide robust authorization throughout your application:
# Authorization methods that work automatically
authorize_current!(resource_record!) # Check permissions for current resource
authorize_current!(resource_class) # Check permissions for resource class
authorize_current!(record, to: :interactive_action?) # Check specific action permission
# Policy access and queries
current_policy # Get policy for current resource
current_policy.allowed_to?(:show?) # Check if action is allowed
policy_for(@user) # Get policy for specific resource
authorized_resource_scope(User) # Get authorized scope for resource class
# Permission helpers
permitted_attributes # Get allowed attributes for current action
permitted_associations # Get allowed associations
Authorization Examples:
class PostsController < ApplicationController
include Plutonium::Resource::Controller
def index
# Authorization is automatically checked against PostPolicy#index?
# No additional code needed
end
def custom_publish
# Check custom permissions
authorize_current!(resource_record!, to: :publish?)
# Your business logic here
PublishPostInteraction.call(post: resource_record!)
redirect_to resource_url_for(resource_record!), success: "Post published!"
end
def conditional_action
# Check permissions before taking action
if current_policy.allowed_to?(:edit?)
redirect_to resource_url_for(resource_record!, action: :edit)
else
redirect_to resource_url_for(resource_record!),
warning: "You don't have permission to edit this post"
end
end
private
def resource_params
# Only permit attributes that the policy allows
params.require(:post).permit(*permitted_attributes)
end
end
Advanced Usage Patterns
Nested Resources: Automatic Relationship Handling
Plutonium automatically handles nested resources based on your ActiveRecord associations:
# Your models define the relationships
class User < ResourceRecord
has_many :posts
has_many :comments
end
class Post < ResourceRecord
belongs_to :user
has_many :comments
end
# Register resources normally
AdminPortal::Engine.routes.draw do
register_resource User
register_resource Post
register_resource Comment
end
# Plutonium automatically creates nested routes:
# /users/:user_id/nested_posts
# /users/:user_id/nested_comments
# /posts/:post_id/nested_comments
Automatic Parent Resolution:
# In a nested route like /users/123/nested_posts/456
current_parent # => User.find(123) - automatically resolved
parent_route_param # => :user_id
parent_input_param # => :user (the belongs_to association name)
# Parameters are automatically merged
resource_params # => includes user: current_parent
Smart URL Generation:
# From within a nested controller context
resource_url_for(Post) # => "/users/123/nested_posts"
resource_url_for(@post) # => "/users/123/nested_posts/456"
resource_url_for(@post, action: :edit) # => "/users/123/nested_posts/456/edit"
# Explicit parent specification
resource_url_for(Post, parent: @user) # => "/users/123/nested_posts"
Multi-Format Response Handling
Plutonium automatically handles different response formats for you. It currently supports HTML, JSON, and Turbo Streams.
Related Modules
The Controller module works seamlessly with other Plutonium components:
- Core: Foundation and essential utilities
- Resource Record: CRUD operations and resource management
- Portal: Multi-tenant portal functionality
- Authentication: User authentication and session management
- Policy: Authorization and access control
- Interaction: Business logic encapsulation
- Routing: Resource registration and route generation