I have a problem similar to the question here but dropping the database isn't a viable solution for my project: Rails 5.2 ActiveStorage undefined method `signed_id' for nil:NilClass
I have a form that allows to upload new images and delete ones that are already uploaded by clicking a link. The form uses Ruby on Rails Active Storage and S3. I followed the answer here to create the link that users can click to delete an image. I think it is deleting the image. However, when the page reloads I get this error
Error: Can't resolve image into URL: undefined method `signed_id' for nil:NilClass
After clicking the "Remove" link, the page should reload and show the remaining images. How do I resolve this error?
Here is the model
class Space < ApplicationRecord
belongs_to :user
has_many_attached :space_image
end
The controller
class SpacesController < ApplicationController
before_action :set_space, except: [:index, :new, :create, :delete_image_attachment]
before_action :authenticate_user!, except: [:show]
def delete_image_attachment
@space_image = ActiveStorage::Blob.find_signed(params[:id])
@space_image.purge_later
redirect_back(fallback_location: spaces_path)
end
private
def set_space
@space = Space.find(params[:id])
end
end
The view
<div>
<% if @space.space_image.attached? %>
<% @space.space_image.each do |space_image| %>
<%= image_tag space_image, class: "avatar-medium" %>
<%= link_to 'Remove', delete_image_attachment_space_url(space_image.signed_id),
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
<% end %>
</div>
** Server error output **
ActionView::Template::Error (Can't resolve image into URL: undefined method `signed_id' for nil:NilClass):
1: <div>
2: <% if @space.space_image.attached? %>
3: <% @space.space_image.each do |space_image| %>
4: <%= image_tag space_image, class: "avatar-medium" %>
5: <%= link_to 'Remove', delete_image_attachment_space_url(space_image.signed_id),
6: method: :delete,
7: data: { confirm: 'Are you sure?' } %>
app/views/spaces/_spaceimg.html.erb:4:in `block in _app_views_spaces__spaceimg_html_erb___4211978368865358240_70218939472720'
app/views/spaces/_spaceimg.html.erb:3:in `_app_views_spaces__spaceimg_html_erb___4211978368865358240_70218939472720'
app/views/spaces/listing.html.erb:121:in `block in _app_views_spaces_listing_html_erb__2591928334825339114_70218934956920'
app/views/spaces/listing.html.erb:15:in `_app_views_spaces_listing_html_erb__2591928334825339114_70218934956920'
This happens because you deleted a record directly from ActiveStorage::Blob, in this way you broke the consistency.
Instead you must find the related record in ActiveStorage::Attachment then delete it: see this line.
Tested in console, so maybe you need to fix some syntax.
space_image.id
should return the id of the record in ActiveStorage::Attachment, so pass it to the controller:
delete_image_attachment_space_url(space_image.id)
Then in controller, just find the record and apply the method you need to delete it:
def delete_image_attachment
@space_image = ActiveStorage::Attachment.find(params[:id])
@space_image.purge
# whatever
end