xiaohongshu
xiaohongshu
plutonium-definition-actions
Add custom actions and interactions to Plutonium resources
Full skill instructions
Actions define custom operations that can be performed on resources. They can be simple (navigation) or interactive (with business logic via Interactions).
| Type | Shows In | Use Case |
|---|---|---|
resource_action | Index page | Import, Export, Create |
record_action | Show page | Edit, Delete, Archive |
collection_record_action | Table rows | Quick actions per row |
bulk_action | Selected records | Bulk operations |
Simple actions link to existing routes. The target route must already exist - these don't create new functionality, just navigation links.
class PostDefinition < ResourceDefinition
# Link to external URL
action :documentation,
label: "Documentation",
route_options: {url: "https://docs.example.com"},
icon: Phlex::TablerIcons::Book,
resource_action: true
# Link to custom controller action (you must add the action + route yourself)
action :reports,
route_options: {action: :reports},
icon: Phlex::TablerIcons::ChartBar,
resource_action: true
end
Important: When adding custom routes for actions, always use the as: option to name them:
# In your portal routes or config/routes.rb
resources :posts do
collection do
get :reports, as: :reports # Named route required!
end
end
This ensures resource_url_for can generate correct URLs, especially for nested resources.
Note: For custom operations with business logic, use Interactive Actions with an Interaction class instead. That's the recommended approach for most custom actions.
class PostDefinition < ResourceDefinition
action :publish,
interaction: PublishInteraction,
icon: Phlex::TablerIcons::Send
action :archive,
interaction: ArchiveInteraction,
color: :danger,
category: :danger,
position: 1000,
confirmation: "Are you sure?"
end
action :name,
# Display
label: "Custom Label", # Button text (default: name.titleize)
description: "What it does", # Tooltip/description
icon: Phlex::TablerIcons::Star, # Icon component
color: :danger, # :primary, :secondary, :danger
# Visibility
resource_action: true, # Show on index page
record_action: true, # Show on show page
collection_record_action: true, # Show in table rows
bulk_action: true, # For selected records
# Grouping
category: :primary, # :primary, :secondary, :danger
position: 50, # Order (lower = first)
# Behavior
confirmation: "Are you sure?", # Confirmation dialog
turbo_frame: "_top", # Turbo frame target
route_options: {action: :foo} # Route configuration
# app/interactions/resource_interaction.rb (generated during install)
class ResourceInteraction < Plutonium::Resource::Interaction
end
# app/interactions/archive_interaction.rb
class ArchiveInteraction < ResourceInteraction
presents label: "Archive",
icon: Phlex::TablerIcons::Archive,
description: "Archive this record"
attribute :resource # The record being acted on
def execute
resource.archived!
succeed(resource).with_message("Record archived successfully.")
rescue ActiveRecord::RecordInvalid => e
failed(e.record.errors)
rescue => error
failed("Archive failed. Please try again.")
end
end
# app/interactions/company/invite_user_interaction.rb
class Company::InviteUserInteraction < Plutonium::Resource::Interaction
presents label: "Invite User", icon: Phlex::TablerIcons::Mail
attribute :resource # The company
attribute :email
attribute :role
# Configure form inputs
input :email, as: :email, hint: "User's email address"
input :role, as: :select, choices: %w[admin member viewer]
# Validations
validates :email, presence: true, format: {with: URI::MailTo::EMAIL_REGEXP}
validates :role, presence: true, inclusion: {in: %w[admin member viewer]}
def execute
UserInvite.create!(
company: resource,
email: email,
role: role,
invited_by: current_user
)
succeed(resource).with_message("Invitation sent to #{email}.")
rescue ActiveRecord::RecordInvalid => e
failed(e.record.errors)
end
end
Bulk actions operate on multiple selected records at once. When a definition has bulk actions, the resource table automatically shows:
# 1. Create the interaction (note: plural `resources` attribute)
class BulkArchiveInteraction < Plutonium::Resource::Interaction
presents label: "Archive Selected", icon: Phlex::TablerIcons::Archive
attribute :resources # Array of records (note: plural)
def execute
count = 0
resources.each do |record|
record.archived!
count += 1
end
succeed(resources).with_message("#{count} records archived.")
rescue => error
failed("Bulk archive failed: #{error.message}")
end
end
# 2. Register the action in the definition
class PostDefinition < ResourceDefinition
action :bulk_archive, interaction: BulkArchiveInteraction
# bulk_action: true is automatically inferred from `resources` attribute
end
# 3. Add policy method
class PostPolicy < ResourcePolicy
def bulk_archive?
create? # Or whatever permission level is appropriate
end
end
Authorization for bulk actions:
bulk_archive?) is checked per record - the backend fails the entire request if any selected record is not authorizedcurrent_authorized_scope - only records the user can access are includedclass ImportInteraction < Plutonium::Resource::Interaction
presents label: "Import CSV", icon: Phlex::TablerIcons::Upload
# No :resource or :resources attribute = resource action
attribute :file
input :file, as: :file
validates :file, presence: true
def execute
# Import logic...
succeed(nil).with_message("Import completed.")
end
end
def execute
# Success with message (redirects to resource automatically)
succeed(resource).with_message("Done!")
# Success with custom redirect (only if different from default)
succeed(resource)
.with_redirect_response(custom_dashboard_path)
.with_message("Redirecting...")
# Failure with field errors
failed(resource.errors)
# Failure with custom message
failed("Something went wrong")
# Failure with specific field
failed("Invalid value", :email)
end
Note: Redirect is automatic on success. Only use with_redirect_response for a different destination.
Inside an interaction:
current_user - The authenticated userview_context - Access to helpers and view methodsdef execute
resource.update!(
archived_by: current_user,
archived_at: Time.current
)
succeed(resource)
end
class PostDefinition < ResourceDefinition
action :publish, interaction: PublishInteraction
action :archive, interaction: ArchiveInteraction
end
class PostDefinition < ResourceDefinition
action :archive,
interaction: ArchiveInteraction,
collection_record_action: false, # Don't show in table
color: :danger,
position: 1000 # Show last
end
Actions defined in ResourceDefinition (created during install) are inherited by all definitions:
# app/definitions/resource_definition.rb (created during install)
class ResourceDefinition < Plutonium::Resource::Definition
action :archive, interaction: ArchiveInteraction, color: :danger, position: 1000
end
# All definitions inherit the archive action automatically
class PostDefinition < ResourceDefinition
end
Override actions for a specific portal:
# packages/admin_portal/app/definitions/admin_portal/post_definition.rb
class AdminPortal::PostDefinition < ::PostDefinition
# Add admin-only actions
action :feature, interaction: FeaturePostInteraction
action :bulk_publish, interaction: BulkPublishInteraction
end
Plutonium provides these by default:
action :new, resource_action: true, position: 10
action :show, collection_record_action: true, position: 10
action :edit, record_action: true, position: 20
action :destroy, record_action: true, position: 100, category: :danger
Actions are authorized via policies:
# app/policies/post_policy.rb
class PostPolicy < ResourcePolicy
def publish?
user.admin? || record.author == user
end
def archive?
user.admin?
end
end
The action only appears if the policy method returns true.
Immediate - Executes without showing a form (when interaction has no extra inputs):
class ArchiveInteraction < Plutonium::Resource::Interaction
attribute :resource # Only resource, no other inputs
# No input declarations
def execute
resource.archived!
succeed(resource)
end
end
Form - Shows a form first (when interaction has additional inputs):
class InviteUserInteraction < Plutonium::Resource::Interaction
attribute :resource
attribute :email
attribute :role
input :email
input :role, as: :select, choices: %w[admin member]
# Has inputs = shows form first
end
class ArchiveInteraction < Plutonium::Resource::Interaction
presents label: "Archive", icon: Phlex::TablerIcons::Archive
attribute :resource
def execute
resource.archived!
succeed(resource).with_message("Archived.")
end
end
class RestoreInteraction < Plutonium::Resource::Interaction
presents label: "Restore", icon: Phlex::TablerIcons::Refresh
attribute :resource
def execute
resource.active!
succeed(resource).with_message("Restored.")
end
end
class SendReminderInteraction < Plutonium::Resource::Interaction
presents label: "Send Reminder", icon: Phlex::TablerIcons::Bell
attribute :resource
attribute :message
input :message, as: :text, hint: "Custom message (optional)"
def execute
ReminderMailer.with(record: resource, message: message).deliver_later
succeed(resource).with_message("Reminder sent.")
end
end
plutonium-definition - Overview and structureplutonium-definition-fields - Fields, inputs, displaysplutonium-definition-query - Search, filters, scopesplutonium-interaction - Writing interaction classesplutonium-policy - Controlling action accessxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience