Fixing Blank Content in ActiveAdmin with Quill Editor and ActionText

Felix D. Helix
January 06, 2026
5 min read
34 views

The Problem: Disappearing Content

Here's how I discovered this bug: I had just launched the blog feature for Career Helix and published my very first blog post. I was excited to share it, promoted it, and moved on to other work.

Almost a week later, I checked the analytics and saw the post had 7 views. Great! People were actually reading it. But when I clicked through to see the post myself, my heart sank.

The entire content was blank. Just a title, metadata, and... nothing.

I immediately went to the ActiveAdmin panel to investigate. When I opened the edit page, the content field was completely empty. What happened?

Then I remembered: I had initially created the post as a draft, written all the content, saved it, and then came back later to change the status from "draft" to "published." That status change must have triggered an update that wiped out all the content.

Seven people had already seen my blank blog post. Embarrassing doesn't begin to describe it.

Worse yet, I realized this could happen again with any blog post edit. This wasn't just a one-time glitch—it was a systematic bug waiting to destroy content.

The Setup

Our Rails 8 application uses:

  1. ActiveAdmin for the admin panel
  2. ActionText (has_rich_text :content) for rich text editing
  3. activeadmin_quill_editor gem for a better editing experience than the default Trix editor

The blog post model looked like this:

class BlogPost < ApplicationRecord
has_rich_text :content
# ... other code
end

And the ActiveAdmin configuration:

ActiveAdmin.register BlogPost do
permit_params :title, :slug, :content, # ... other params
form do |f|
f.inputs 'Content' do
f.input :content, as: :quill_editor
end
# ... rest of form
end
end

Seemed straightforward, right? Wrong.

Initial Investigation

First, I checked if the content actually existed in the database:

rails runner "post = BlogPost.first; puts post.content.body.present?"# => true

The content was there. So why wasn't it showing in the edit form?

I tried the obvious fix—eager loading the ActionText content:

controller do
def find_resource
scoped_collection.with_rich_text_content.find_by!(slug: params[:id])
end
end

Still blank.

I tried setting the value explicitly in the form:

f.input :content, as: :quill_editor,
input_html: {
value: (f.object.content.body.to_html if f.object.content.body.present?)
}

Nope. Still nothing.

The Root Cause

After some digging, I found the real issue: the activeadmin_quill_editor gem doesn't support ActionText's has_rich_text associations.

Here's why:

  1. ActionText stores content separately: When you use has_rich_text :content, Rails stores the actual content in a separate action_text_rich_texts table with polymorphic associations
  2. Quill expects a string field: The activeadmin_quill_editor gem expects a simple string or text column, not an ActionText association
  3. The form can't read the association: When the form tries to populate the Quill editor, it's looking for a content string attribute, but instead finds an ActionText::RichText object that it doesn't know how to handle

Result? Blank field in the editor.

The Solution

The fix comes from the gem's official documentation, specifically this GitHub issue comment.

The solution is to create wrapper methods that act as a bridge between ActionText and the Quill editor.

Step 1: Add Wrapper Methods to Your Model

class BlogPost < ApplicationRecord
has_rich_text :content
# Workaround for activeadmin_quill_editor compatibility with ActionText
# See: https://github.com/blocknotes/activeadmin_quill_editor/issues/33#issuecomment-1965996947
def quill_content
content&.body&.to_s&.html_safe
end
def quill_content=(value)
self.content = value
end
end

What this does:

  1. Getter (quill_content): Extracts the HTML body from the ActionText object and returns it as a safe HTML string that Quill can read
  2. Setter (quill_content=): Takes the HTML from the form submission and assigns it to the ActionText content attribute

Step 2: Update ActiveAdmin to Use the Wrapper

Change your ActiveAdmin resource to use quill_content instead of content:

ActiveAdmin.register BlogPost do
# Update permitted parameters
permit_params :title, :slug, :quill_content, # ... other params (NOT :content)
# Update the form
form do |f|
f.inputs 'Content' do
f.input :quill_content, as: :quill_editor,
input_html: {
data: {
options: {
modules: {
toolbar: [
[{ header: [1, 2, 3, 4, 5, 6, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ list: 'ordered' }, { list: 'bullet' }],
['blockquote', 'code-block'],
['link'],
['clean']
]
}
}.to_json
}
}
end
# ... rest of form
end
# Update the show page if you display content there
show do
attributes_table do
# ... other rows
end
panel 'Content' do
div do
blog_post.quill_content
end
end
end
end

Step 3: Restart Your Server

ActiveAdmin configurations are loaded at startup, so you need to restart your Rails server for the changes to take effect.

Why This Worked

The wrapper methods solve the impedance mismatch between ActionText and Quill:

  1. On form load: quill_content extracts the HTML from ActionText and provides it as a plain string to the Quill editor
  2. On form submit: quill_content= receives the edited HTML and saves it back to ActionText
  3. ActionText handles the rest: Once the content is assigned via self.content = value, ActionText takes care of storing it in the action_text_rich_texts table

The beauty of this approach is that it's completely transparent to the rest of your application. Everywhere else in your code, you still use @blog_post.content as normal.

Conclusion

This was a critical bug that risked losing published content. The fix is straightforward once you understand the incompatibility between activeadmin_quill_editor and ActionText.

If you're using this gem combination, implement the wrapper methods now—before you accidentally save a blank post.


Share this post

Ready to Organize Your Job Search?

Join Career Helix and track your applications, interviews, and offers in one place.

Sign Up for Free

Premium free for 30 days