Maksym Prokopov personal blog
Idea is a something worth sharing

Adding PDF previews to ActionText with ActiveStorage

15.09.2025
Reading time: 2 min.

Rails is a great framework, once you stop thinking in Java patterns and embraice DHH way of writing web apps.

Interestingly, Basecamp uses exactly the same ActiveStorage implementation, but shows full-size and download links alone with the PDF attachment. But if you only follow the guide, it’s hard to implement by your own without some gotchas.

These gotchas I want to capture here in this how-to article. It assumes reader followed official guide and stuck with PDF thumbnails preview implementation.

PDF Previews

For download and view full-size links, standard template should be improved.

Create views/active_storage/preview/_blob.html.erb

<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>
    <span class="attachment__attribute attachment__attribute--download">
      <%= link_to 'View full-size', rails_blob_path(blob), target: '_blank' %>
    </span>
    <span class="attachment__attribute attachment__attribute--download">
      <%= link_to 'Download', rails_blob_path(blob, disposition: "attachment"), target: '_blank' %>
    </span>
    <% end %>
  </figcaption>
</figure>

Dockerfile

Official documentation mentions Poppler project as a dependency.

So, don’t forget to install poppler-utils in Dockerfile

RUN apt-get update --fix-missing -qq && apt-get install -y build-essential nodejs libcurl4 git-core \
    libxml2-dev libmariadb-dev imagemagick libyaml-dev poppler-utils

For macOS it’s as simple as brew install poppler

ApplicationController

in application controller include SetCurrent concern, to enable local disk support.

  include ActiveStorage::SetCurrent

During the deployment, if you use Amazon S3, it’s important to set CORS policy, otherwise the preview will fail

Mailer Previews

In mailer preview, the helper rails_blob_path can’t be found, so let’s address it with the full path

Rails.application.routes.url_helpers.rails_blob_path(blob)

End snippet is

<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 ]).processed.url %>
  <% 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>
      <span class="attachment__attribute attachment__attribute--download">
          <%= link_to 'View full-size', Rails.application.routes.url_helpers.rails_blob_path(blob) %>
      </span>
      <span class="attachment__attribute attachment__attribute--download">
          <%= link_to 'Download', Rails.application.routes.url_helpers.rails_blob_path(blob, disposition: "attachment") %>
      </span>
    <% end %>
  </figcaption>
</figure>

CORS configuration

[
    {
        "AllowedHeaders": [
            "Origin",
            "Content-Type",
            "Content-MD5",
            "Content-Disposition"
        ],
        "AllowedMethods": [
            "PUT"
        ],
        "AllowedOrigins": [
            "*.it-premium.internal"
        ],
        "ExposeHeaders": [
            "Access-Control-Allow-Origin"
        ]
    }
]