Rails 6.1 -> 7 gives 404 for ActionText attachments

Hello

I’ve recently upgraded a project from Rails 6.1 → 7 and noticed that in production I’m receiving 404s on ActionText attachments.

I can’t see anything in the upgrade guide that needs to be actioned around ActionText specifically.

When I look at the RichText record where the images fail, I can see that body.attachments has a number of RemoteImage attachables that were uploaded to the 6.1 app. These are producing 404s

When I upload a new image to the record under 7.x, it is being attached to the record as a Blob and displays correctly.

Anyone have any pointers for me on this?

ActionText relies on ActiveStorage, which generates encrypted urls. When you submit, ActionText saves that URL as part of the HTML code, so if something causes ActiveStorage urls to change, the urls in ActionText will no longer work.

The migration from rails 6 to 7 changed the key generator from SHA1 to SHA256, which should have impacted the urls in ActiveStorage, which in turn must have broken your images. Here’s a sample code I used to fix mine:

  # After active storage urls are changed, use this to recreate all trix attachments
  def self.refresh_trixes
    ActionText::RichText.where.not(body: nil).find_each do |trix|
      refresh_trix(trix)
    end
  end

  # After active storage urls are changed, use this to recreate a specific trix attachments
  def self.refresh_trix(trix)
    return unless trix.embeds.size.positive?

    trix.body.fragment.find_all("action-text-attachment").each do |node|
      embed = trix.embeds.find { |attachment| attachment.filename.to_s == node["filename"] && attachment.byte_size.to_s == node["filesize"] }

      node.attributes["url"].value = Rails.application.routes.url_helpers.rails_storage_redirect_url(embed.blob, host: "YOUR_DOMAIN")
      node.attributes["sgid"].value = embed.attachable_sgid
    end

    trix.update_column :body, trix.body.to_s
  end

Pleas make sure you test this before running in production. I’ve used a few times and it works well enough, but you never know… and also replace YOUR_DOMAIN with your actual domain.

1 Like

You are a legend, thank you.

Is there something I missed or is this some undocumented behaviour?

It’s undocumented. I had to read through the code to figure out why images were broken and how to fix them. Since I rely heavily in signed_id, I’ve created this initializer to block deploy in case something we did caused them to change (which would break action text and a lot of other things)

Rails.application.config.after_initialize do
  if Rails.env.production? && User.find_signed("A_SAMPLE_SIGNED_ID").nil?
    raise ArgumentError, "Something has changed the signed ids. DO NOT DEPLOY"
  end
end

So I grabbed my user, did user.signed_id in production, and placed the result in A_SAMPLE_SIGNED_ID. This way, next time something like the SHA causes the signed ids to change the initializer will raise and block my deploy.

1 Like

That’s quite an oof …

Are we the only two people that use ActionText?

Probably not many apps using action text, and even less who made the Rails 6 → 7 migration already. But I know of another dev, who maintains a blogging sass, who had the same problem and came with a similar solution to mine after also reading through the source code