
plutonium-definition-actions
by radioactive-labs
Build production-ready Rails apps in minutes, not days. Convention-driven, fully customizable, AI-ready.
SKILL.md
name: plutonium-definition-actions description: Add custom actions and interactions to Plutonium resources
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
| 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 (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
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 userview_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 structureplutonium-definition-fields- Fields, inputs, displaysplutonium-definition-query- Search, filters, scopesplutonium-interaction- Writing interaction classesplutonium-policy- Controlling action access
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon
