Rails 6 introduces Action Text to provide WYSIWYG support in Rails


This is part one of our multipart series exploring Action Text.

Before

Before introduction to Action Text, adding support for rich-text fields, or WYSIWYG editors was cumbersome. We would choose from several available options like TinyMCE, Trix, and so on. After adding this in views, support to handle file uploads, storage of text and converting back and forth from view vs database, supporting plugins, etc on the backend, were some of the repetitive tasks we would spend time on.

Action Text

Action Text is a new framework introduced as part of Rails 6 that makes it easy to work with rich text content.

Action Text combines Trix Editor, Active Storage, and ActiveRecord to provide the following features:

  • Creating and editing the rich text
  • Storing and rendering the rich text
  • Ability to attach and render attachment within rich text editor
  • Seamlessly upload the attached files to the chosen cloud provider

Trix

Trix is developed by Basecamp.

According to its official website:

Trix is an editor for writing messages, comments, articles, and lists—the simple documents most web apps are made of. It features a sophisticated document model, support for embedded attachments, and outputs terse and consistent HTML.

You can read more about Trix, all the features it offers, and what are its advantages over most other WYSIWYG editors over here.

Setup Action Text

To setup Action Text, we can run the following command from root directory of a Rails 6 app:

$ rails action_text:install

Above command will perform the following steps:

  • Update package.json to add packages for actiontext and trix.
  • Add a migration to create tables needed to support storage of rich text content.
  • Add a migration to create tables needed by Active Storage.
  • Add app/views/active_storage/blobs/_blob.html.erb: we can modify this file to change how the image uploads and other attachments are rendered.
  • Add app/assets/stylesheets/actiontext.scss: we can modify this file to change the styling of Trix editor.

Use a rich text field with an existing model

To add a rich text field to an existing model:

# app/models/post.rb
class Post < ApplicationRecord
  has_rich_text :content
end 

Note: content is not an actual field on the posts table. The rich text data is stored in a internal table called action_text_rich_texts.

We can use helper method rich_text_area to render the field in the form:

<%# app/views/posts/_form.html.erb %>
<%= form_with(model: post) do |form| %>
  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>
<% end %> 

This shows an editor like so:

The rich text is stored in database as HTML content.

We can get the rich text as html string simply by calling method corresponding to the field name. For example, in case of Post model describer above we can use #content method.

This is how we can render the content in an html view:

<%# app/views/posts/show.html.erb %>
<%= @post.content %>

Note, we need to add image_processing gem to enable rendering of attached images.

gem 'image_processing', '~> 1.2'

In its absence LoadError (cannot load such file -- mini_magick): error will be thrown while working with images.

Custom styling

We can modify app/assets/stylesheets/actiontext.scss, to change styling of Trix editor and the content.

To modify how the attachments are rendered we can update app/views/active_storage/blobs/_blob.html.erb. For example you can add a download link to each rendered attachment. The code would look something like below:

<%# app/views/active_storage/blobs/_blob.html.erb %>
<%
  figure_class = [
      "attachment",
      "attachment--#{blob.representable? ? 'preview' : 'file'}",
      "attachment--#{blob.filename.extension}",
  ].join(" ")
  resize_limit = local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]
  blob_representation = blob.representation(resize_to_limit: resize_limit )
%>
<figure class=<%=figure_class%>>
  <% if blob.representable? %>
    <%= image_tag blob_representation %>
  <% end %>

  <figcaption class="attachment__caption">
    <% if caption = blob.try(:caption) %>
      <%= caption %>
    <% else %>
      <span class="attachment__name"><%= blob.filename %></span>
    <% end %>
    |
    <%
      # This is the line we added.
      # Everthing else is was already present when the file was created during action text setup
    %>
    <%= link_to "Download", rails_blob_path(blob, disposition: "attachment") %>
  </figcaption>
</figure>

This shows up like:

Summary

We looked at basic of how we can get started with providing WYSIWYG support in our Apps using ActionText. In our next post of the series we will look at how to manage and render different types of attachments, media, and more.