Skip to content
plutonium-definition-actions logo

Definition Actions

plutonium-definition-actions

Add custom actions and interactions to Plutonium resources

SKILL.md

Full skill instructions

Definition Actions

Actions define custom operations that can be performed on resources. They can be simple (navigation) or interactive (with business logic via Interactions).

Action Types

TypeShows InUse Case
resource_actionIndex pageImport, Export, Create
record_actionShow pageEdit, Delete, Archive
collection_record_actionTable rowsQuick actions per row
bulk_actionSelected recordsBulk operations

Simple Actions (Navigation)

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.

Interactive Actions (with Interaction)

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 Options

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

Creating an Interaction

Basic Structure

# 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

With Additional Inputs

# 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 Action (Multiple Records)

Bulk actions operate on multiple selected records at once. When a definition has bulk actions, the resource table automatically shows:

  • Selection checkboxes in each row
  • Bulk actions toolbar that appears when records are selected
# 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:

  • Policy method (e.g., bulk_archive?) is checked per record - the backend fails the entire request if any selected record is not authorized
  • Records are fetched via current_authorized_scope - only records the user can access are included
  • The UI only shows action buttons that all selected records support (intersection of allowed actions)

Resource Action (No Record)

class 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

Interaction Responses

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.

Interaction Context

Inside an interaction:

  • current_user - The authenticated user
  • view_context - Access to helpers and view methods
def execute
  resource.update!(
    archived_by: current_user,
    archived_at: Time.current
  )
  succeed(resource)
end

Defining in Definition

Basic

class PostDefinition < ResourceDefinition
  action :publish, interaction: PublishInteraction
  action :archive, interaction: ArchiveInteraction
end

With Overrides

class PostDefinition < ResourceDefinition
  action :archive,
    interaction: ArchiveInteraction,
    collection_record_action: false,  # Don't show in table
    color: :danger,
    position: 1000                    # Show last
end

Inherited Actions

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

Portal-Specific Actions

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

Default CRUD Actions

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

Authorization

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 vs Form Actions

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

Common Patterns

Archive/​Restore

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

Send Notification

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

Related Skills

  • plutonium-definition - Overview and structure
  • plutonium-definition-fields - Fields, inputs, displays
  • plutonium-definition-query - Search, filters, scopes
  • plutonium-interaction - Writing interaction classes
  • plutonium-policy - Controlling action access

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

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...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

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...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

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.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View