Lexxy Rich Text Templates đ
This feature provides AI-powered rich text template integration using Lexxy, allowing users to create reusable prompt templates with category-based filtering and slash command access.
Overviewâ
The Lexxy Rich Text Templates feature introduces:
- CmPrompt Model: Stores reusable rich text templates with category associations
- Lexxy Integration: AI-powered slash commands (
/) in rich text editors - Category-Based Filtering: Organize templates by categories for easy access
- Policy Scoping: Role-based access control for template visibility
- Dynamic Scopes: Automatic scope methods for category filtering (e.g.,
estimation_only)
Installationâ
1. Run the Generatorâ
rails generate cm_admin:add_prompts_with_constants
This creates two migrations:
create_cm_prompts- Creates the prompts tablecreate_constant_maps- Creates the polymorphic association table
2. Run Migrationsâ
rails db:migrate
3. Add CmPrompt to Included Modelsâ
Update your CM Admin configuration:
# config/initializers/zcm_admin.rb
CmAdmin.configure do |config|
config.included_models = [Constant, User, CmRole, DemoForm, CmPlatformSetting, CmSupportTicket, CmCronJob, CmCronJobLog, ApiToken, CmPrompt]
# ... other configuration
end
4. Add Lexxy Template Platform Settingâ
The generator automatically adds a platform setting for the default Lexxy template. You can configure it in the admin panel under Platform Settings > RichText Templates.
Model Structureâ
CmPromptâ
class CmPrompt < ApplicationRecord
has_rich_text :prompt
has_many :categories, as: :mappable, dependent: :destroy, class_name: 'ConstantMap'
has_many :constants, through: :categories
validates :name, :slug, presence: true, uniqueness: { case_sensitive: false }
end
Fields:
name- Template name (required, unique)slug- URL-friendly identifier (auto-generated from name)prompt- Rich text content (ActionText)created_by- User who created the templateupdated_by- User who last updated the template
ConstantMapâ
Polymorphic association table linking Constants to any model:
class ConstantMap < ApplicationRecord
belongs_to :constant
belongs_to :mappable, polymorphic: true
end
Usageâ
Creating Templatesâ
- Navigate to Cm Prompts in the admin panel
- Click New Cm Prompt
- Fill in the template details:
- Name: Template name (e.g., "Project Estimation")
- Slug: Auto-generated, can be customized
- Categories: Select one or more categories from
cm_prompt_categoryconstants - Prompt: Rich text content with formatting
- Save the template
Using Templates in Rich Text Fieldsâ
When editing any rich text field in the admin panel:
- Type
/in the rich text editor - A dropdown appears with available templates
- Select a template to insert its content
- The template content is inserted as editable text
Category-Based Filteringâ
Templates can be filtered by category using dynamic scope methods:
# Filter by specific category
CmPrompt.with_category('Estimation')
# Dynamic scope method (auto-generated from category name)
CmPrompt.estimation_only
CmPrompt.documentation_only
CmPrompt.reporting_only
The _only suffix is automatically added to category names to create scope methods.
Policy Scopingâ
Templates respect role-based access control through policy scopes:
class CmPromptPolicy < ApplicationPolicy
class RichTextTemplateScope < Scope
def resolve
# Implement your access control logic
# Example: Only show templates for user's categories
scope.all
end
end
end
The policy scope name must follow the pattern: CmAdmin::{ModelName}PolicyRichTextTemplateScope
Platform Settingsâ
A new platform setting is added for Lexxy configuration:
- Lexxy Template: The default Lexxy template to use
Access this in Platform Settings > RichText Templates.
API Endpointsâ
Rich Text Templates Endpointâ
# lib/cm_admin/constants.rb
rich_text_templates: {
verb: :get,
path: 'rich_text_templates'
}
This endpoint is used by the Lexxy integration to fetch available templates.
Technical Detailsâ
Lexxy Integrationâ
The Lexxy prompt system is integrated into rich text fields via the build_lexxy_prompt helper:
def build_lexxy_prompt
policy_scope_name = "CmAdmin::#{@model.ar_model.name}PolicyRichTextTemplateScope"
templates = policy_scope_name.constantize.new(Current.user, ::CmPrompt).resolve
template_items = templates.map { |t| build_lexxy_item(t) }.join
<<~HTML.html_safe
<lexxy-prompt trigger="/" name="template" insert-editable-text>#{template_items}</lexxy-prompt>
HTML
end
Dynamic Scope Methodsâ
The CmPrompt model uses method_missing to create dynamic scope methods:
def self.method_missing(method_name, *args, &)
if method_name.to_s.end_with?('_only')
category_name = method_name.to_s.gsub('_only', '').titleize
with_category(category_name)
else
super
end
end
This allows calling CmPrompt.estimation_only which internally calls CmPrompt.with_category('Estimation').
Category Association Managementâ
Categories are managed through the category_ids virtual attribute:
def category_ids=(ids)
@category_ids = Array(ids).reject(&:blank?)
end
def create_category_associations
return if @category_ids.blank?
categories.destroy_all
@category_ids.each do |category_id|
categories.create(constant_id: category_id)
end
end
Database Schemaâ
cm_prompts Tableâ
create_table :cm_prompts do |t|
t.string :name, null: false
t.citext :slug, null: false
t.references :created_by, foreign_key: { to_table: :users }
t.references :updated_by, foreign_key: { to_table: :users }
t.timestamps
end
add_index :cm_prompts, :name, unique: true
add_index :cm_prompts, :slug, unique: true
constant_maps Tableâ
create_table :constant_maps do |t|
t.references :constant, null: false
t.references :mappable, polymorphic: true, null: false
t.timestamps
end
add_index :constant_maps, %i[constant_id mappable_id mappable_type], unique: true
Dependenciesâ
This feature requires:
- Lexxy (~> 0.8) - AI-powered rich text editor integration
- ActionText - Rails rich text framework
- pg_trgm PostgreSQL extension (for citext support)
Troubleshootingâ
Templates Not Appearing in Editorâ
- Check Policy Scope: Ensure the policy scope returns templates for the current user
- Verify Categories: Ensure templates have at least one category assigned
- Check Lexxy Configuration: Verify the Lexxy template platform setting is configured
Category Scope Methods Not Workingâ
- Verify Category Name: Ensure the category exists in
cm_prompt_categoryconstants - Check Naming Convention: Use the
_onlysuffix (e.g.,estimation_only) - Review Category Association: Ensure templates are properly associated with categories
Migration Errorsâ
If the constant_maps table already exists, the migration will skip creation:
return if table_exists?(:constant_maps)
Examplesâ
Creating a Template with Categoriesâ
# In Rails console
template = CmPrompt.create!(
name: 'Project Estimation Template',
slug: 'project-estimation',
prompt: '<h1>Project Estimation</h1><p>Enter your estimation details...</p>',
category_ids: [1, 2] # IDs of cm_prompt_category constants
)
Filtering Templates by Categoryâ
# Using scope method
estimation_templates = CmPrompt.estimation_only
# Using with_category
documentation_templates = CmPrompt.with_category('Documentation')
# Combining with other scopes
recent_estimation = CmPrompt.estimation_only.order(created_at: :desc).limit(10)
Accessing Template Categoriesâ
template = CmPrompt.first
template.category_names # => "Estimation, Documentation"
template.category_ids # => [1, 2]
Future Enhancementsâ
Potential improvements for this feature:
- Template versioning with history tracking
- Template preview before insertion
- Template variables/placeholders support
- Template sharing between users
- Template analytics (usage tracking)