Ruby on Rails - Active storage - Can not display image using image_tag but CAN use <img src=model.attachment.url>?

37 views Asked by At

I have recently been trying to implement Ruby on Rails' ActiveStorage. My setup is pretty simple but I am having issues using the <%= image_tag... with my uploaded files. I am serving files out of AWS S3. Here is my test setup: storage.yml

# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
amazon:
  service: S3
  # Instad of specifying these or using Rails.application.credentials we can rely on env vars or any other valid way of authenticating the aws sdk gem
  access_key_id:     # Hard coded creds right now for testing
  secret_access_key: # Hard coded creds right now for testing
  region: us-east-1
  bucket: test-my-s3-bucket-name

I have been testing using a model called personnel

class Personnel < ApplicationRecord
  ...
  # NEW ACTIVESTORAGE CODE
  has_one_attached :as_photo
  # OPTIONAL:
  validates :as_photo, size: { less_than: 3.megabytes , message: 'is too large' },
                       content_type: {in: ['image/jpeg', 'image/png', 'image/gif', 'image/pjpeg', 'image/x-png'],
                                      message: I18n.t("errors.file_invalid_format", :formats => "JPG,GIF,PNG") }

  before_save :define_attachment_key
  # This method will generate a string based on the model name
  # This string is used in the file's key name on S3. This is how we place files into s3 "sub folders" for organizational/browsing purposes
  def photo_path
    # This key has to be unique across all assets which is why we call ActiveRecord::SecureToken.generate_unique_secure_token
    # modelname/uuid but you could create further subdivisions if you wanted. modelname/attachment1/uuid & modelname/attachment2/uuid for example
    "public/#{Rails.env}/models/#{self.class.name}/photo/#{ActiveStorage::Blob.generate_unique_secure_token}"
  end

  def define_attachment_key
    as_photo.key = photo_path if as_photo.new_record?
    # add any additional ..._path methods here if there are multiple attachments on this model you want subfolders for.
    # Attachments without a ..._path method will placed at the root of the bucket
  end

I then have a test route pointing to this template

<h1>Personnel</h1>
<h2>There are a total of <%= @count %> Personnel records</h2>

<ul>
  <% @persons.each do |person| %>
    <li>
      <%= person.id %>
      <% if person.as_photo.present? %>
        <ul>
          <li>
              <%= image_tag(person.as_photo) %>
          </li>
          <li>
            Proxy: <%= image_tag rails_storage_proxy_path(person.as_photo) %>
          </li>
          <li>
            img tag with as.url: <img src="<%= person.as_photo.url %>" alt="an image wow">
          </li>
        </ul>
      <% end %>
    </li>
  <% end %>
</ul>

But as you can see, only 1 of these 3 ways of rendering the image displayspersonnel profile pic I think the URL being supplied by the different methods has something to do with it. The person.as_photo.url url looks like a presigned AWS url while the 2 other methods that use simply person.as_photo and an image_tag (like examples in the doc use) seem to produce a URL that somehow routes through the rails server first, and those are the ones that don't work (404). http://localhost:3000/rails/active_storage/blobs/proxy & http://localhost:3000/rails/active_storage/blobs/redirect

1

There are 1 answers

0
Rosey On

Got it. This question helped me figure it out. Apparently Activestorage appends it's own routes to the master route file. If you have a catch-all/wildcard route that would catch rails/active_storage/... (like I did. get '*path', to: ...) then you need to carve out an exception for rails/active_storage routes.