Claude-skill-registry plutonium-controller
Plutonium resource controllers - CRUD actions, customization, and integration
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/controller" ~/.claude/skills/majiayu000-claude-skill-registry-plutonium-controller && rm -rf "$T"
skills/data/controller/SKILL.mdPlutonium Controllers
Controllers in Plutonium provide full CRUD functionality out of the box. You rarely need to customize them - definitions handle most UI configuration and policies handle authorization.
Base Classes
# app/controllers/resource_controller.rb (generated during install) class ResourceController < ApplicationController include Plutonium::Resource::Controller end # app/controllers/posts_controller.rb (generated per resource) class PostsController < ::ResourceController # Empty - all CRUD actions inherited end
What You Get for Free
Every resource controller automatically provides:
| Action | Route | Purpose |
|---|---|---|
| GET /posts | List with pagination, search, filters, sorting |
| GET /posts/:id | Display single record |
| GET /posts/new | New record form |
| POST /posts | Create record |
| GET /posts/:id/edit | Edit record form |
| PATCH /posts/:id | Update record |
| DELETE /posts/:id | Delete record |
Plus interactive action routes for custom operations defined in definitions.
When to Customize
Use Definitions for:
- Field configuration (inputs, displays, columns)
- Search, filters, scopes, sorting
- Actions (interactive operations)
- Form customization
Customize Controller for:
- Custom redirect logic
- Special parameter processing
- Non-standard authorization flows
- External integrations
- Response format changes
Override Hooks
All customization is done by overriding private methods:
Redirect Hooks
class PostsController < ::ResourceController private # Where to go after create/update: "show" (default), "edit", "new", "index" def preferred_action_after_submit "edit" end # Custom URL after create/update (overrides preferred_action_after_submit) def redirect_url_after_submit posts_path end # Custom URL after destroy def redirect_url_after_destroy posts_path end end
Parameter Hooks
class PostsController < ::ResourceController private # Modify params before create/update def resource_params params = super params[:tags] = params[:tags].split(",") if params[:tags].is_a?(String) params end end
Query Hooks
class PostsController < ::ResourceController private # Customize the index query def filtered_resource_collection base = current_authorized_scope base = base.featured if params[:featured] current_query_object.apply(base, raw_resource_query_params) end end
Presentation Hooks
Control whether parent/entity fields appear in forms and displays:
class PostsController < ::ResourceController private # Show parent field in displays (default: false) def present_parent? true end # Include parent field in forms (default: same as present_parent?) def submit_parent? true end # Show scoped entity in displays (default: false) def present_scoped_entity? true end # Include scoped entity in forms (default: same as present_scoped_entity?) def submit_scoped_entity? true end end
Custom Actions
class PostsController < ::ResourceController def publish authorize_current!(resource_record!, to: :publish?) resource_record!.update!(published: true) redirect_to resource_url_for(resource_record!), notice: "Published!" end end
Important: When adding custom routes, always use the
as: option to name them:
# config/routes.rb or portal routes resources :posts do member do post :publish, as: :publish # Named route required! end end
This ensures
resource_url_for can generate correct URLs, especially for nested resources.
Note: For most custom operations, use Interactive Actions in definitions instead.
Key Methods
Resource Access
resource_class # The model class (e.g., Post) resource_record! # Current record (raises if not found) resource_record? # Current record (nil if not found) resource_params # Permitted params for create/update current_parent # Parent record for nested routes
Authorization
authorize_current!(record, to: :action?) # Check permission current_policy # Policy for current resource permitted_attributes # Allowed attributes for action current_authorized_scope # Scoped records user can access
Definition Access
current_definition # Definition for current resource
UI Building
build_form # Build form component build_detail # Build show/detail component build_collection # Build table component
URL Generation
resource_url_for(@post) # URL for record resource_url_for(@post, action: :edit) # Edit URL resource_url_for(Post) # Index URL # With parent (nested resources) resource_url_for(@comment, parent: @post) # Nested URL resource_url_for(Comment, action: :new, parent: @post) # Cross-package URLs resource_url_for(@post, package: AdminPortal)
Nested Resources
Parent records are automatically resolved from routes with the
nested_ prefix:
# Route: /users/:user_id/nested_posts/:id class PostsController < ::ResourceController # current_parent returns the User # current_nested_association returns :posts # resource_record! returns the Post scoped to that User end
Key Methods for Nested Resources
current_parent # Parent record (e.g., User instance) current_nested_association # Association name (e.g., :posts) parent_route_param # URL param (e.g., :user_id) parent_input_param # Form param (e.g., :user)
Parent fields are automatically excluded from forms/displays. Override with presentation hooks (see above).
has_one Support
For
has_one associations, routes are singular:
(no/users/:user_id/nested_profile
param):id- Index redirects to show (or new if no record exists)
Entity Scoping (Multi-tenancy)
When a portal is scoped to an entity:
# packages/admin_portal/lib/engine.rb module AdminPortal class Engine < Rails::Engine include Plutonium::Portal::Engine config.after_initialize do scope_to_entity Organization, strategy: :path end end end
Controllers automatically:
- Scope all queries to the entity
- Exclude entity field from forms
- Provide
methodcurrent_scoped_entity
Authorization Verification
Controllers verify authorization was performed:
# These run after every action verify_authorize_current # Ensures authorize_current! was called verify_current_authorized_scope # Ensures scope was loaded (except new/create)
To skip verification for custom actions:
class PostsController < ::ResourceController skip_verify_authorize_current only: [:custom_action] def custom_action # Handle authorization manually end end
Response Formats
Controllers respond to multiple formats:
def show # Responds to: # - HTML (default) # - JSON (via RABL templates) # - Turbo Stream (for Hotwire) end
Portal-Specific Controllers
Each portal can have its own controller override. Portal controllers inherit from the feature package's controller:
# packages/admin_portal/app/controllers/admin_portal/posts_controller.rb class AdminPortal::PostsController < ::PostsController include AdminPortal::Concerns::Controller private def preferred_action_after_submit "index" # Admin prefers list view end end
Controllers are auto-created if not defined. When accessing a portal resource, Plutonium dynamically creates the controller by inheriting from the feature package's controller.
For non-resource portal pages (dashboard, settings), inherit from
PlutoniumController:
module AdminPortal class DashboardController < PlutoniumController def index # Dashboard home end end end
Best Practices
- Keep controllers thin - Use definitions for UI, policies for auth, interactions for logic
- Don't override CRUD actions - Customize via hooks (
,resource_params
)redirect_url_after_submit - Use interactive actions - For custom operations, define in definition with interaction
- Let authorization work - Don't skip verification without good reason
- Trust the framework - Most customization belongs in definitions or policies
Related Skills
- How controllers fit in the resource architectureplutonium-resource
- Authorization (used by controllers)plutonium-policy
- Interactive actions (preferred over custom controller actions)plutonium-definition-actions
- Custom page, form, display, and table classesplutonium-views
- Parent/child routes and scopingplutonium-nested-resources
- Resource modelsplutonium-model