Reputation: 5908
I'm having 404's trying to use ActiveStorage. Here's the code:
class Model
has_many_attached :attachments, dependent: :destroy
# In form
<%= form.file_field :attachments, multiple: true %>
# In controller
def model_request_params
params.require(:model_name).permit(:title, attachments: [])
end
# In config/storage.yml
local:
service: Disk
root: <%= Rails.root.join("storage") %>
# In development.rb
config.active_storage.service = :local
# In view
<%#= image_tag @model_instance.attachments.first %>
When I open the browser, the generated HTML is like this:
http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3814080e8c7e26964c927840a18034d727c61d87/file.jpg
, but this returns a 404 not found.
The weird thing is that I have a different Rails 5.2.0 project and as soon as this GET is fired, the server console shows Precessing by ActiveStorage::Blobs Controller.
On this project however, I only see this:
Started GET "/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3814080e8c7e26964c927840a18034d727c61d87/file.jpg" for 127.0.0.1 at 2018-07-23 12:15:36 -0300
It is NOT followed by anything else, not indicating any controller or whatever, but the browser gets a 404 and the image is never loaded.
I can confirm the attachment is uploaded, because not only model_instance.attachments[0]
returns a ActiveStorage::Attachment, but the file is also present in my project's storage/
folder.
Rails version: 5.2.0 (not brand new, updated - I don't see this bug in a brand new Rails 5.2.0 app)
Ruby version: 2.3.6
Upvotes: 4
Views: 2531
Reputation: 63
My problem also seemed to be that my queue adapter wasn't running in development, so the images could not be processed
config.active_job.queue_adapter = :inline
in development.rb fixed that for me
Upvotes: 0
Reputation: 5908
Here's the culprit, I had this at the very beginning of my routes.rb file:
if Rails.env.development?
scope format: true, constraints: { format: /jpg|png|gif|PNG/ } do
get '/*anything', to: proc { [404, {}, ['']] }
end
end
I had totally forgotten about this hack. Here's some context:
We frequently dump the production database to our dev machines to have an up-to-date dev environment. But we do NOT copy the entire public/uploads folder because it's crazy huge.
This makes so that many of the pages that link to uploaded assets are VERY slow to load, because each image hits the dev application server which errors out with 404.
After this slowing us down for years, we found this excellent solution in a makandra card:
When you load a dump for development, records may reference images that are not available on your machine. Requests to those images may end up on your application, e.g. if a catch-all route is defined that leads to a controller doing some heavy lifting. On pages with lots of missing images, this slows down development response times. You can fix that by defining a Rails route like this: (code above)
Images are (usually) served directly from public or assets and won't hit your controllers/routes, as long as the files exist. If files are missing, the request will be handled by the above route which instantly responds with an empty HTTP 404 response.
Needless to say, that hacky fix was hijacking the /rails routes used by ActiveStorage because they satisfied the constraint.
I can't comment on makandra cards, but I hope Google will bring people here.
In the meantime, I changed the hack to this:
if Rails.env.development?
scope format: true, constraints: { format: /jpg|png|gif|PNG/ } do
get '/*anything', to: proc { [404, {}, ['']] }, constraints: lambda { |request| !request.path_parameters[:anything].start_with?('rails/') }
end
end
Upvotes: 4