Rails ActiveStorage does not save attachment performed within a scope of ActiveJob

81 Views Asked by At

I have an ActiveJob, which downloads the image from the URL and attaches it to the ActiveRecord instance. Within the scope of a job the attachment works fine - I can read back the blob successfully. However, when I try to access the same record with attachment from the console, the blob is not attached. Looks like rails bug to me.

This is the job code:

require 'open-uri'

class DownloadJob < ActiveJobStatus::TrackableJob

  queue_as :default

  def perform(image)
    begin
      downloaded_image = URI.parse(image.url).open
      image.data.attach(io: downloaded_image, filename: image.filename)
      image.save
      puts "Attached: #{image.data.attached?}" # True
      puts "Filename: #{image.filename}" # Shows proper filename
      puts "Blob: #{image.data.download}" # Displays blob
      image.image_downloaded = true
      image.url_is_valid = true
    rescue StandardError => e
      puts "EXCEPTION!!! #{e}"
      image.url_is_valid = false
    end
    image.save
  end
end

And the code executed in the console:

i = Image.second
j = DownloadJob.perform_later(i)
i.data.attached? # false
i.data.download # nil

I see the downloaded image blobs in the storage directory of the project. I see them in both tables: active_storage_blobs and active_storage_attachments.

My Image model has custom primary key "url", which may be the cause of an issue as I can't identify by which columns rails references model instances in the activestorage tables

1

There are 1 best solutions below

1
Sergey Panov On

I have nailed it. The issue is indeed string primary key of the ActiveRecord. I have modified the field in the db migration file and it worked.

change this:

create_table :active_storage_attachments, id: primary_key_type do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false, type: :foreign_key_type
      t.references :blob,     null: false, type: foreign_key_type

      if connection.supports_datetime_with_precision?
        t.datetime :created_at, precision: 6, null: false
      else
        t.datetime :created_at, null: false
      end

      t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end

to this:

create_table :active_storage_attachments, id: primary_key_type do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false, type: :string
      t.references :blob,     null: false, type: foreign_key_type

      if connection.supports_datetime_with_precision?
        t.datetime :created_at, precision: 6, null: false
      else
        t.datetime :created_at, null: false
      end

      t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end