Action Text Video Support

Action Text

Here’s a quick post just to document how I got video uploads working in Action Text, again mostly for “future me”, but hopefully helpful for others!

Let me say, I love Action Text and Trix. For me at least its exactly what I need for simple text input that users can format and also upload images. I won’t go into the details of how to set it up as there are countless great sources for that, the primary one of course being the Rails Guides which are great.

File uploads

One of the killer features of Action Text in my opinion is the way it handles file uploads so simply with a WYSIWYG interface. This is great for images but I couldn’t figure out why I couldn’t play uploaded .mov video files. And I really needed this for my use case of sharing technical issues and bug reports.

Default Templates

When you install Action Text with bin/rails action_text:install the default template for representing attachments will be generated in app/views/active_storage/blobs/_blob.html.erb and looks like this (Rails 8.0.0.alpha)

<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
  <% if blob.representable? %>
    <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
  <% end %>

  <figcaption class="attachment__caption">
    <% if caption = blob.try(:caption) %>
      <%= caption %>
    <% else %>
      <span class="attachment__name"><%= blob.filename %></span>
      <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
    <% end %>
  </figcaption>
</figure>

I found that a thumbnail of the video was generated and displayed when I rendered out the content but I wanted to play the video! I expected adding something like this using the AssetTagHelper for video would render accordingly:

<% if blob.video? %>
    <%= video_tag url_for(blob), controls: true, preload: "metadata", class: "attachment__video" %>
...

but while I got a great preview still image of the video, I couldn’t play it…

Sanitization

Finally after a lot of head scratching I discovered that the tags were being sanitized away. Sanitizing the form input is critical since users may try all kinds of nefarious exploits to compromise our sites, but in this case supporting video seemed to be an ok trade-off.

The trick then is to allow the video related tags in the HTML to be rendered when showing Action Text content. To do this we need to add the following initializer in config/initializers/action_text.rb:

Rails.application.config.after_initialize do
  default_allowed_attributes = Rails::HTML5::Sanitizer.safe_list_sanitizer.allowed_attributes + ActionText::Attachment::ATTRIBUTES.to_set
  custom_allowed_attributes = Set.new(%w[controls])
  ActionText::ContentHelper.allowed_attributes = (default_allowed_attributes + custom_allowed_attributes).freeze

  default_allowed_tags = Rails::HTML5::Sanitizer.safe_list_sanitizer.allowed_tags + Set.new([ ActionText::Attachment.tag_name, "figure", "figcaption" ])
  custom_allowed_tags = Set.new(%w[audio video source])
  ActionText::ContentHelper.allowed_tags = (default_allowed_tags + custom_allowed_tags).freeze
end

What this is doing is telling Action Text to allow a “controls” HTML attribute and “audio”, “video” and “source” tags to be rendered from user uploaded content.

After restarting the server.. voila! You should see a video play button and scrub control!

Wrap Up

As always, don’t hesitate to drop me a note via twitter or any other channels listed here.