Claude-skill-registry plutonium-definition-query
Configure search, filters, scopes, and sorting for Plutonium resources
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/definition-query" ~/.claude/skills/majiayu000-claude-skill-registry-plutonium-definition-query && rm -rf "$T"
skills/data/definition-query/SKILL.mdDefinition Query
Configure how users can search, filter, and sort resource collections.
Overview
class PostDefinition < ResourceDefinition # Search - global text search search do |scope, query| scope.where("title ILIKE ?", "%#{query}%") end # Filters - dropdown filter panel filter :title, with: :text, predicate: :contains filter :status, with: :select, choices: %w[draft published archived] filter :published, with: :boolean filter :created_at, with: :date_range filter :category, with: :association # Scopes - quick filter buttons scope :published scope :draft # Sorting - sortable columns sort :title sort :created_at # Default sort default_sort :created_at, :desc end
Search
Define global search across fields:
# Single field search do |scope, query| scope.where("title ILIKE ?", "%#{query}%") end # Multiple fields search do |scope, query| scope.where( "title ILIKE :q OR content ILIKE :q OR author_name ILIKE :q", q: "%#{query}%" ) end # With associations search do |scope, query| scope.joins(:author).where( "posts.title ILIKE :q OR users.name ILIKE :q", q: "%#{query}%" ).distinct end # Split search terms search do |scope, query| terms = query.split(/\s+/) terms.reduce(scope) do |current_scope, term| current_scope.where("title ILIKE ?", "%#{term}%") end end
Filters
Plutonium provides 6 built-in filter types. Use shorthand symbols or full class names.
Text Filter
String/text filtering with pattern matching.
# Shorthand (recommended) filter :title, with: :text, predicate: :contains filter :status, with: :text, predicate: :eq # Full class name filter :title, with: Plutonium::Query::Filters::Text, predicate: :contains
Predicates:
| Predicate | SQL | Description |
|---|---|---|
| | Exact match (default) |
| | Not equal |
| | Contains substring |
| | Does not contain |
| | Starts with |
| | Ends with |
| | Pattern match ( becomes ) |
| | Does not match pattern |
Boolean Filter
True/false filtering for boolean columns.
# Basic filter :active, with: :boolean # Custom labels filter :published, with: :boolean, true_label: "Published", false_label: "Draft"
Renders a select dropdown with "All", true label ("Yes"), and false label ("No").
Date Filter
Single date filtering with comparison predicates.
filter :created_at, with: :date, predicate: :gteq # On or after filter :due_date, with: :date, predicate: :lt # Before filter :published_at, with: :date, predicate: :eq # On exact date
Predicates:
| Predicate | Description |
|---|---|
| On this date (default) |
| Not on this date |
| Before date |
| On or before date |
| After date |
| On or after date |
Date Range Filter
Filter between two dates (from/to).
# Basic filter :created_at, with: :date_range # Custom labels filter :published_at, with: :date_range, from_label: "Published from", to_label: "Published to"
Renders two date pickers. Both are optional - users can filter with just "from" or just "to".
Select Filter
Filter from predefined choices.
# Static choices (array) filter :status, with: :select, choices: %w[draft published archived] # Dynamic choices (proc) filter :category, with: :select, choices: -> { Category.pluck(:name) } # Multiple selection filter :tags, with: :select, choices: %w[ruby rails js], multiple: true
Association Filter
Filter by associated record.
# Basic - infers Category class from :category key filter :category, with: :association # Explicit class filter :author, with: :association, class_name: User # Multiple selection filter :tags, with: :association, class_name: Tag, multiple: true
Renders a resource select dropdown. Converts filter key to foreign key (
:category -> :category_id).
Custom Filters
Custom Filter Class
class PriceRangeFilter < Plutonium::Query::Filter def apply(scope, min: nil, max: nil) scope = scope.where("price >= ?", min) if min.present? scope = scope.where("price <= ?", max) if max.present? scope end def customize_inputs input :min, as: :number input :max, as: :number field :min, placeholder: "Min price..." field :max, placeholder: "Max price..." end end # Use in definition filter :price, with: PriceRangeFilter
Scopes
Scopes appear as quick filter buttons. They reference model scopes.
Basic Usage
class PostDefinition < ResourceDefinition scope :published # Uses Post.published scope :draft # Uses Post.draft scope :featured # Uses Post.featured end
Inline Scope
Use block syntax with the scope passed as an argument:
scope(:recent) { |scope| scope.where('created_at > ?', 1.week.ago) } scope(:this_month) { |scope| scope.where(created_at: Time.current.all_month) }
With Controller Context
Inline scopes have access to controller context like
current_user:
scope(:mine) { |scope| scope.where(author: current_user) } scope(:my_team) { |scope| scope.where(team: current_user.team) }
Default Scope
Set a scope as default to apply it when no scope is explicitly selected:
class PostDefinition < ResourceDefinition scope :published, default: true # Applied by default scope :draft scope :archived end
When a default scope is set:
- The default scope is applied on initial page load
- The default scope button is highlighted (not "All")
- Clicking "All" shows all records without any scope filter
- URL without scope param uses the default; URL with
uses "All"?q[scope]=
Sorting
Basic Sorting
sort :title sort :created_at sort :view_count # Multiple at once sorts :title, :created_at, :view_count
Default Sort
# Field and direction default_sort :created_at, :desc default_sort :title, :asc # Complex sorting with block default_sort { |scope| scope.order(featured: :desc, created_at: :desc) }
Note: Default sort only applies when no sort params are provided.
URL Parameters
Query parameters are structured under
q:
/posts?q[search]=rails /posts?q[title][query]=widget /posts?q[status][value]=published /posts?q[created_at][from]=2024-01-01&q[created_at][to]=2024-12-31 /posts?q[scope]=recent /posts?q[sort_fields][]=created_at&q[sort_directions][created_at]=desc
Filter Summary Table
| Type | Symbol | Input Params | Options |
|---|---|---|---|
| Text | | | |
| Boolean | | | , |
| Date | | | |
| Date Range | | , | , |
| Select | | | , |
| Association | | | , |
Complete Example
class ProductDefinition < ResourceDefinition # Full-text search search do |scope, query| scope.where( "name ILIKE :q OR description ILIKE :q", q: "%#{query}%" ) end # Filters filter :name, with: :text, predicate: :contains filter :status, with: :select, choices: %w[draft active discontinued] filter :featured, with: :boolean filter :created_at, with: :date_range filter :price, with: :date, predicate: :gteq filter :category, with: :association # Quick scopes scope :active, default: true scope :featured scope(:recent) { |scope| scope.where('created_at > ?', 1.week.ago) } # Sortable columns sorts :name, :price, :created_at # Default sort default_sort :created_at, :desc end
Performance Tips
- Add indexes for filtered/sorted columns
- Use
when joining associations in search.distinct - Consider
for complex full-text searchpg_search - Limit search fields to indexed columns
- Use scopes instead of filters for common queries
Related Skills
- Overview and structureplutonium-definition
- Fields, inputs, displaysplutonium-definition-fields
- Actions and interactionsplutonium-definition-actions