- Update ActiveAdmin from beta16 to beta20 - Drop support for Rails 6.1, 7.0, 7.1 and ActiveAdmin 2.x/3.x - Minimum requirements now: Rails 7.2+, Ruby 3.2+, ActiveAdmin 4.x - Reduce CI jobs from 22+ to 6 (2 gemfiles × 3 Ruby versions) - Clean up obsolete documentation files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.8 KiB
CKEditor5-Rails Upload System Documentation
Overview
The CKEditor5-Rails gem implements a flexible image upload system that allows users to upload images directly from the editor to a server endpoint instead of embedding them as Base64. The system is designed to be backend-agnostic and can integrate with various storage solutions including ActiveStorage and Shrine.
Architecture
Core Components
1. SimpleUploadAdapter Plugin (lib/ckeditor5/rails/plugins/simple_upload_adapter.rb)
The heart of the upload system is an inline JavaScript plugin that:
- Extends CKEditor5's Plugin class
- Requires the FileRepository plugin as a dependency
- Implements the upload adapter factory pattern
- Handles file uploads via XMLHttpRequest with progress tracking
Location: lib/ckeditor5/rails/plugins/simple_upload_adapter.rb
Key Features:
- Async/await based upload handling
- Progress tracking through XMLHttpRequest events
- CSRF token integration for Rails security
- Abort capability for cancelled uploads
- JSON response parsing for uploaded file URLs
2. PropsInlinePlugin Base Class (lib/ckeditor5/rails/editor/props_inline_plugin.rb)
The upload adapter extends this base class which:
- Wraps JavaScript code in an async IIFE (Immediately Invoked Function Expression)
- Supports optional code compression via Terser
- Provides window-based plugin registration mechanism
- Handles plugin initialization errors gracefully
Location: lib/ckeditor5/rails/editor/props_inline_plugin.rb
3. Plugin Registration System (lib/ckeditor5/rails/plugins.rb)
Central registry that:
- Loads all core plugins including SimpleUploadAdapter
- Manages plugin dependencies
- Handles plugin patches and fixes
Location: lib/ckeditor5/rails/plugins.rb
Configuration System
Preset Builder Integration (lib/ckeditor5/rails/presets/preset_builder.rb)
The upload adapter is configured through the preset system:
def simple_upload_adapter(upload_url = '/uploads', compress: !@disallow_inline_plugin_compression)
plugins do
remove(:Base64UploadAdapter) # Remove default Base64 adapter
end
plugin(Plugins::SimpleUploadAdapter.new(compress: compress))
configure(:simpleUpload, { uploadUrl: upload_url })
end
Location: lib/ckeditor5/rails/presets/preset_builder.rb:394-401
Configuration Steps:
- Removes the default Base64UploadAdapter plugin
- Adds the SimpleUploadAdapter plugin
- Configures the upload URL endpoint
- Optionally enables/disables JavaScript compression
Usage in Presets
Upload functionality is enabled in presets via:
# In preset definition
simple_upload_adapter # Uses default '/uploads' endpoint
simple_upload_adapter '/custom' # Custom endpoint
Example Location: sandbox/config/initializers/ckeditor5.rb:82
Frontend Implementation
Upload Flow
- User Action: User selects/pastes an image in the editor
- Plugin Activation: FileRepository triggers createUploadAdapter
- Adapter Creation: SimpleUploadAdapter creates an upload instance
- FormData Preparation: File wrapped in FormData with 'upload' field name
- Security Headers:
- X-Requested-With: XMLHttpRequest
- X-CSRF-Token: Extracted from meta tag
- Upload Process:
- Progress events update loader.uploaded/uploadTotal
- Success (200-299): Parse JSON response for URL
- Error handling for failed/aborted uploads
- Editor Update: Returned URL replaces placeholder image
Response Format
Server must return JSON with structure:
{
"url": "https://example.com/uploads/image.jpg"
}
Integration Points
1. Rails Controller
The upload endpoint (not included in gem) should:
- Accept POST requests to configured URL
- Process multipart/form-data with 'upload' field
- Store file using preferred backend (ActiveStorage, Shrine, etc.)
- Return JSON with uploaded file URL
- Handle CSRF token validation
2. Helper Methods
Upload configuration accessible via:
ckeditor5_editorhelper in views- Preset configuration in initializers
- Runtime configuration overrides
Location: lib/ckeditor5/rails/editor/helpers/editor_helpers.rb
3. Engine Registration
Upload adapter available through:
- Engine preset system
- Direct plugin inclusion
- Configuration DSL methods
Location: lib/ckeditor5/rails/engine.rb:83
File Structure
lib/ckeditor5/rails/
├── plugins/
│ ├── simple_upload_adapter.rb # Main upload adapter implementation
│ └── ...
├── editor/
│ ├── props_inline_plugin.rb # Base class for inline plugins
│ └── helpers/
│ └── editor_helpers.rb # View helpers for editor
├── presets/
│ └── preset_builder.rb # Configuration DSL with upload method
└── engine.rb # Rails engine with upload registration
Configuration Examples
Basic Setup
CKEditor5::Rails.configure do
# Enable with default /uploads endpoint
simple_upload_adapter
end
Custom Endpoint
CKEditor5::Rails.configure do
# Custom upload endpoint
simple_upload_adapter '/api/images/upload'
end
With Compression Disabled
CKEditor5::Rails.configure do
# Disable JavaScript compression for debugging
simple_upload_adapter '/uploads', compress: false
end
Key Implementation Details
JavaScript Plugin Structure
The plugin is written as an ES6 module that:
- Imports required CKEditor5 modules dynamically
- Returns a class extending Plugin
- Implements standard CKEditor5 plugin lifecycle
- Integrates with FileRepository for upload management
Security Considerations
- CSRF token automatically extracted from Rails meta tag
- XMLHttpRequest marked with X-Requested-With header
- Server-side validation responsibility lies with implementer
Error Handling
- Network errors caught and rejected with descriptive messages
- HTTP status codes outside 200-299 range treated as errors
- Upload abort capability for user cancellation
Backend Requirements
To implement the upload endpoint:
- Route Definition: Add POST route to configured URL
- File Processing: Handle multipart upload with 'upload' parameter
- Storage Backend: Integrate with ActiveStorage, Shrine, or custom solution
- Response Format: Return JSON with 'url' key
- Security: Validate CSRF tokens and user permissions
Extension Points
The system supports:
- Multiple upload adapters via plugin system
- Custom configuration through preset builder
- Backend flexibility through endpoint abstraction
- Compression toggle for development/production
- Integration with various storage backends
This architecture provides a clean separation between the editor frontend and storage backend, allowing developers to implement uploads using their preferred Rails patterns and storage solutions.