This content originally appeared on DEV Community and was authored by Lucas Barret
Action Text is a ruby gem that is part of Rails. It enables you to write and display rich text in your app.
But how does it work ?
Install Action Text
First thing first let’s set up our issue. You want to create a blog.
Obviously in this blog you have articles.
You create an article table and in this table you have a content column.
Eventually you decide that you would like to add rich text to these article content.
You use Action Text, so let’s install it :
bin/rails action_text:install
This generates a migration so you just need to run them.
Eventually in your model article.rb you just have to add has_rich_text :content and Voilà !
How this table works
This table is a polymorphic table where you store the name of the record and the id of the record.
A row from this table look like this :
ActiveRecord::Base.connection.execute("select * from action_text_rich_texts")
{
"id" => 3,
"body" => "the body of your content",
"created_at" => "2025-10-26 10:39:22.112279",
"name" => "content",
"record_id" => 2,
"record_type" => "Article",
"updated_at" => "2025-10-26 17:17:09.672582"
}
And when you update your article content like this :
Article.find(2).update(content: 'new content')
It will not update the content of the article but the body of the related action_text_rich_text.
Article.find(2).attributes
{
"id" => 2,
"content" => nil, # content is nil
"created_at" => 2025-10-26 10:39:22.106595000 UTC +00:00,
"updated_at" => 2025-10-26 17:17:09.674060000 UTC +00:00
}
ActiveRecord::Base.connection.execute("select * from action_text_rich_texts")
{
"id" => 3,
"body" => "new content",
"created_at" => "2025-10-26 10:39:22.112279",
"name" => "content",
"record_id" => 2,
"record_type" => "Article",
"updated_at" => "2025-10-26 17:17:09.672582"
}
How is this working ?
This is done in fact through a simple trick : redefining the getter of the Article class.
And this is done thought the has_rich_text dsl that you use earlier.
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}=(body)
self.#{name}.body = body
end
CODE
And why it works ? Because create use new that use the getter to affect variable with the setter of the class.
This also means that the bulk edit method, like insert_all and update_all does not work.
Conclusion
That’s it you know how rich text work and how the magic happens
This content originally appeared on DEV Community and was authored by Lucas Barret