Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveStorage Image Upload Error with Rails 5.2: signed_id delegated to attachment, but attachment is nil

I'm having an issue with image/pdf uploads with ActiveStorage. The images appear to be uploading without issue, but they are causing errors when I try to show them.

My blog model has_one_attached :image and has_one_attached :pdf. The uploads used to work (so I know I have ActiveStorage installed and my amazon s3 set up properly), but something has gone wrong.

The only complicated bit is I need it to work if it has a PDF or not (not all blogs will have a pdf...all should have an image).

My blog#create method is:

  def create
    @blog = Blog.new(blog_params)
    @blog.user_id = current_user.id
    if @blog.published
      @blog.published_on = DateTime.current
    end

    respond_to do |format|
      if @blog.save
        if @blog.image.attached?
          @blog.image.purge
        end
        @blog.image.attach(params[:image])
        if @blog.pdf.attached?
          @blog.pdf.purge
        end
        @blog.pdf.attach(params[:pdf])
        format.html { redirect_to @blog, notice: 'Blog was successfully created.' }
        format.json { render :show, status: :created, location: @blog }
      else
        format.html { render :new }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

My blog#update method is:

  def update
    if @blog.published
      @blog.published_on = DateTime.current
    end
    if @blog.image.attached?
      @blog.image.purge
    end
    @blog.image.attach(params[:image])
    if @blog.pdf.attached?
      @blog.pdf.purge
    end
    @blog.pdf.attach(params[:pdf])
    respond_to do |format|
      if @blog.update(blog_params)
        format.html { redirect_to @blog, notice: 'Blog was successfully updated.' }
        format.json { render :show, status: :ok, location: @blog }
      else
        format.html { render :edit }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

My form is simple:

<%= simple_form_for(@blog) do |f| %>
  <%= f.error_notification %>
  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>

...
    <div class="form-group">
      <%= f.label "Blog Image" %><br />
      <%= f.file_field :image %>
    </div>
    <div class="form-group">
      <%= f.label "Linked PDF" %><br />
      <%= f.file_field :pdf %>
    </div>

...

  <div class="form-actions text-center">
    <%= f.button :submit, class: "btn-outline-primary" %>
  </div>
<% end %>

I'm trying to show the image in the blog like this:

<div class="frame" style="background-image: url(<%= rails_blob_url(@blog.image) %>)"></div>

And the PDF like this:

<h2 class="cta text-center"><%= link_to @blog.cta, rails_blob_url(@blog.pdf), target: "_blank" %></h2>

The error I'm getting is signed_id delegated to attachment, but attachment is nil on the place the image is called as a background image on the blog#show page. I get the same error on localhost and Heroku, if it helps.

Finally, I saw this error on this question and did try dropping and recreating my database, but to no avail.

Can anyone see what's going wrong here?

like image 659
Liz Avatar asked Sep 20 '18 01:09

Liz


People also ask

What's new in rails active storage?

The new approach to file uploads | Prograils Update: Rails and Active Storage. The new approach to file uploads Since its first shipping, Active Storage has revolutionized attaching files to Ruby on Rails applications. Learn what it is, how to set it up and use it, as well what's new in Rails Active Storage in 2021!

How does active storage handle image variants?

If a variant is requested, Active Storage will automatically apply transformations depending on the image's format: Content types that are variable (as dictated by config.active_storage.variable_content_types ) and not considered web images (as dictated by config.active_storage.web_image_content_types ), will be converted to PNG.

How are new files uploaded to the secondary services?

New files are directly uploaded to the primary service. When a directly-uploaded file is attached to a record, a background job is enqueued to copy it to the secondary services. By default, Active Storage assumes private access to services. This means generating signed, single-use URLs for blobs.

How do I test if a file uploads but does not attach?

Using Direct Uploads can sometimes result in a file that uploads, but never attaches to a record. Consider purging unattached uploads. Use fixture_file_upload to test uploading a file in an integration or controller test. Rails handles files like any other parameter. System tests clean up test data by rolling back a transaction.


1 Answers

I just ran into this error and really struggled to figure out what could have been happening. It first appeared when I submitted a form and did not include an attachment. Turns out I needed to check to see if something was really attached and deal with that possibility.

Perhaps try moving @blog.pdf.attach(params[:pdf]) to before the respond_to in blog#create

Then, when trying to show the image, maybe you could try something like this

<% if blog.pdf.attached? == false %>
  <p>No pdf attached</p>
<% elsif blog.pdf.previewable? %>
  <%= link_to(image_tag(blog.pdf.preview(resize: "50x50>")),  rails_blob_path(blog.pdf, disposition: "attachment"))
%>
<% elsif blog.pdf.variable? %>
  <%= link_to(image_tag(blog.pdf.variant(resize: "50x50")), rails_blob_path(blog.pdf, disposition: "attachment"))%>
<% else %>
  <%= link_to "Download file", rails_blob_path(@blog.pdf, disposition: "attachment") %>
<% end %>

Heroku has a good article on active storage here that may also help.

like image 61
nniroclax Avatar answered Sep 28 '22 09:09

nniroclax