Help us improve
Share bugs, ideas, or general feedback.
From majestic-rails
Adds Tiptap rich text editing with debounced autosave to Rails models using Stimulus controllers, storing markdown in plain text columns (not ActionText). For inline editing UIs without ActionText.
npx claudepluginhub majesticlabs-dev/majestic-marketplace --plugin majestic-railsHow this skill is triggered — by the user, by Claude, or both
Slash command
/majestic-rails:rails-tiptap-autosaveThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Add rich text editing with automatic background saving to any Rails model using Tiptap, Stimulus, and markdown stored in plain text columns.
Guides building reactive Rails apps with Hotwire (Turbo Drive/Frames/Streams, Stimulus): installation, ActionCable/Redis setup, core patterns.
Implements Hotwire Turbo (Drive, Frames, Streams, Morph) and Stimulus controllers in Rails views for SPA-like interactivity, real-time updates, and progressive enhancement.
Implements Tiptap extensions for Umbraco's Rich Text Editor, adding custom nodes, marks, or capabilities via manifests and API classes using official docs.
Share bugs, ideas, or general feedback.
Add rich text editing with automatic background saving to any Rails model using Tiptap, Stimulus, and markdown stored in plain text columns.
Key decision: Markdown in text columns, NOT ActionText.
How it works:
update_column| File | Purpose |
|---|---|
app/javascript/controllers/rich_text_editor_controller.js | Tiptap Stimulus controller |
app/views/shared/_rich_text_field.html.erb | Reusable editor partial |
app/views/shared/_bubble_menu.html.erb | Formatting toolbar |
npm packages, @rails/request.js for CSRF, JS bundler setup (Tiptap does not work with importmap), and editor CSS.
See: references/installation.md
Full rich_text_editor_controller.js — Tiptap initialization, debounced autosave, BubbleMenu target relocation, Turbo cache cleanup, and bubble menu formatting commands.
See: references/stimulus-controller.md
Reusable _rich_text_field.html.erb and _bubble_menu.html.erb with Stimulus data attributes.
See: references/partials.md
Debounced change tracking that groups rapid edits into single audit events.
See: references/audit-trail.md
class AddBodyToArticles < ActiveRecord::Migration[7.1]
def change
add_column :articles, :body, :text # Must be :text, NOT :string (255 char limit)
end
end
resources :articles do
member { patch :autosave }
end
AUTOSAVE_FIELDS = %w[body summary notes].freeze
def autosave
field = params[:field].to_s
return render json: { error: "field not allowed" }, status: :bad_request unless AUTOSAVE_FIELDS.include?(field)
@article.update_column(field.to_sym, params[:value])
render json: { status: "saved" }
end
Key points:
update_column bypasses validations/callbacks — correct for autosave performanceset_article must include :autosave in only: list<%= render "shared/rich_text_field",
url: autosave_article_path(@article),
field: "body",
content: @article.body,
placeholder: "Write your article...",
label: "Body" %>
Each field gets its own controller instance. Each is fully independent:
<%= render "shared/rich_text_field", url: autosave_article_path(@article),
field: "body", content: @article.body, label: "Body" %>
<%= render "shared/rich_text_field", url: autosave_article_path(@article),
field: "summary", content: @article.summary, label: "Summary" %>
# Gemfile: gem "redcarpet"
module MarkdownHelper
def render_markdown(text)
return "" if text.blank?
renderer = Redcarpet::Render::HTML.new(hard_wrap: true, filter_html: true)
markdown = Redcarpet::Markdown.new(renderer, autolink: true, tables: true,
fenced_code_blocks: true, strikethrough: true)
markdown.render(text).html_safe
end
end
<div class="prose prose-sm max-w-none"><%= render_markdown(@article.body) %></div>
text, not string (255-char limit silently truncates)patch :autosave member route must exist or you get 404sset_article must include :autosave in only: listbroadcasts_refreshes on models with Tiptap — Turbo morphing destroys editor mid-edit. Scope broadcasts to exclude the editing user.has_rich_text declarations.references/installation.md.this.bubbleMenuTarget unreachable. Save a reference before calling new Editor(). See references/stimulus-controller.md.turbo:before-cache handling. Destroy the editor and restore DOM before Turbo caches the page. See references/stimulus-controller.md.