Skip to content

Working with Resources

What you'll learn

  • How to create and manage resources in Plutonium
  • Understanding resource definitions and configurations
  • Working with fields, associations, and nested resources
  • Implementing resource policies and scoping
  • Best practices for resource organization

Introduction

Resources are the core building blocks of a Plutonium application. A resource represents a model in your application that can be managed through a consistent interface, complete with views, controllers, and policies.

Creating a Resource

The fastest way to create a resource is using the scaffold generator:

bash
rails generate pu:res:scaffold Blog user:belongs_to \
  title:string content:text 'published_at:datetime?'

This generates several files, including:

ruby
class Blog < ResourceRecord
  belongs_to :user
end
ruby
class BlogPolicy < Plutonium::Resource::Policy
  def create?
    true
  end

  def read?
    true
  end

  def permitted_attributes_for_create
    %i[user title content published_at]
  end

  def permitted_attributes_for_read
    %i[user title content published_at]
  end
end
ruby
class BlogDefinition < Plutonium::Resource::Definition
end

Resource Definitions

Resource definitions customize how a resource behaves in your application. They define:

  • Fields and their types
  • Available actions
  • Search and filtering capabilities
  • Sorting options
  • Display configurations

Basic Field Configuration

ruby
class BlogDefinition < Plutonium::Resource::Definition
  # Basic field definitions
  field :content, as: :text

  # Field with custom display options
  field :published_at,
        as: :datetime,
        hint: "When this post should be published"
end
ruby
class BlogDefinition < Plutonium::Resource::Definition
  # Customize how fields are displayed
  display :title, class: "col-span-full"
  display :content, class: "col-span-full" do |f|
    f.text_tag class: "prose dark:prose-invert"
  end

  # Custom column display in tables
  column :published_at, align: :end
end

Adding Custom Actions

Beyond CRUD, you can add custom actions to your resources:

ruby
# app/interactions/blogs/publish.rb
module Blogs
  class Publish < Plutonium::Resource::Interaction
    # Define what this interaction accepts
    attribute :resource, class: Blog
    attribute :publish_date, :date, default: -> { Time.current }

    presents label: "Publish Blog",
             icon: Phlex::TablerIcons::Send,
             description: "Make this blog post public"

    private

    def execute
      if resource.update(
        published_at: publish_date
      )
        succeed(resource)
          .with_message("Blog post published successfully")
          .with_redirect_response(resource)
      else
        failed(resource.errors)
      end
    end
  end
end

# app/definitions/blog_definition.rb
class BlogDefinition < Plutonium::Resource::Definition
  # Register the custom action
  action :publish,
    interaction: Blogs::Publish,
    category: :primary
end

Search and Filtering

Add search and filtering capabilities to your resources:

ruby
class BlogDefinition < Plutonium::Resource::Definition
  # Enable full-text search
  search do |scope, query|
    scope.where("title ILIKE ? OR content ILIKE ?",
      "%#{query}%", "%#{query}%")
  end

  # Add filters
  filter :published_at,
    with: DateFilter,
    predicate: :gteq

  # Add scopes
  scope :published do |scope|
    scope.where.not(published_at: nil)
  end
  scope :draft do |scope|
    scope.where(published_at: nil)
  end

  # Configure sorting
  sort :title
  sort :published_at
end

Resource Policies

Policies control access to your resources:

ruby
class BlogPolicy < Plutonium::Resource::Policy
  def permitted_attributes_for_create
    %i[title content state published_at user_id]
  end

  def permitted_associations
    %i[comments]
  end

  def create?
    # Allow logged in users to create blogs
    user.present?
  end

  def update?
    # Users can only edit their own blogs
    record.user_id == user.id
  end

  def publish?
    # Only editors can publish
    user.editor? && record.draft?
  end

  # Scope visible records
  relation_scope do |relation|
    relation = super(relation)
    next relation unless user.admin?

    relation.with_deleted
  end
end

Best Practices

Resource Organization

  1. Keep resource definitions focused and cohesive
  2. Use packages to organize related resources
  3. Leverage policy scopes for authorization
  4. Extract complex logic into interactions
  5. Use presenters for view-specific logic

Common Pitfalls

  • Avoid putting business logic in definitions
  • Don't bypass policy checks
  • Remember to scope resources appropriately
  • Test your interactions and policies

Released under the MIT License.