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 displays
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
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 forrails/active_storageroutes.