Rails 5.2 ActiveStorage with UUID on PostgreSQL

brvekthn  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(3)|浏览(109)

我们的应用程序使用uuid作为主键,在PostgreSQL数据库上。(标准设置描述为here)。
我们按照here描述的过程集成了ActiveStorage。使用rails active_storage:install的标准设置,并使用rails db:migrate进行迁移。
我们有一个模型和相应的控制器如下:

# Model
class Message < ApplicationRecord
  has_one_attached :image

  def filename
    image&.attachment&.blob&.filename
  end
end

# Controller
class MessagesController < ApplicationController
  def create
    message = Message.create!(message_params)
    redirect_to message
  end

  private
    def message_params
      params.require(:message).permit(:title, :content, :image)
    end
end

我们观察到,前几组图像与模型示例正确关联,但随后我们使用模型示例获得随机图像,或者根本没有图像。每次,我们重新启动服务器,我们得到了前几张正确的图像,但后来它是不可预测的。
不确定出了什么问题,我们在rails控制台中进行了调试:

params[:image]
=> #<ActionDispatch::Http::UploadedFile:0x007fcf2fa97b70 @tempfile=#<Tempfile:/var/folders/dt/05ncjr6s52ggc4bk6fs521qw0000gn/T/RackMultipart20180726-8503-vg36kz.pdf>, @original_filename="sample.pdf", @content_type="application/pdf", @headers="Content-Disposition: form-data; name=\"file\"; filename=\"sample.pdf\"\r\nContent-Type: application/pdf\r\n">

在保存示例并检索文件名时,我们得到了一个随机文件,我们之前上传了。

@message = Message.new(message_params)
@message.filename
=> #<ActiveStorage::Filename:0x007fcf32cfd9e8 @filename="sample.pdf">

@message.save

@message.filename
=> #<ActiveStorage::Filename:0x007f82f2ad4ef0 @filename="OtherSamplePdf.pdf">

寻找这种奇怪行为的解释,以及可能的解决方案。

erhoui1w

erhoui1w1#

在activestorage source code中逐行查看并运行相同的命令数小时后,

@message = Message.new(message_params)
@message.save

一次又一次我们一次又一次地得到同样的随机结果。然后,我们查看了在将图像附加到消息时打印的日志轨道,并观察到以下情况:

S3 Storage (363.4ms) Uploaded file to key: KBKeHJARTjnsVjkgSbbii4Bz (checksum: S0GjR1EyvYYbMKh44wqlag==)

ActiveStorage::Blob Create (0.4ms)  INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["key", "KBKeHJARTjnsVjkgSbbii4Bz"], ["filename", "sample.pdf"], ["content_type", "application/pdf"], ["metadata", "{\"identified\":true}"], ["byte_size", 3028], ["checksum", "S0GjR1EyvYYbMKh44wqlag=="], ["created_at", "2018-07-26 04:54:33.029769"]]

ActiveStorage::Attachment Create (2.7ms)  INSERT INTO "active_storage_attachments" ("name", "record_type", "record_id", "blob_id", "created_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["name", "file"], ["record_type", "Message"], ["record_id", "534736"], ["blob_id", "0"], ["created_at", "2018-07-26 05:04:35.958831"]]

record_id被设置为534736,而不是UUID。我们错在这里。

**Active storage在我们的Message模型中需要整数外键,我们希望它使用uuids。**所以我们必须修复我们的迁移,使用uuids而不是整数外键。

解决方案:

class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    create_table :active_storage_blobs, id: :uuid do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
    end

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

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
    end
  end
end

希望这对面临类似问题的人有所帮助。干杯!

jei2mxaa

jei2mxaa2#

我在2020年的聚会上迟到了,但正如anurag所提到的,这是由于active_storage_attachments DB表使用了record_id的bigint。我无法将所有带有ActiveStorage附件的模型迁移到UUID,所以我需要一种同时支持UUID和bigint的方法。
警告:如果你能避免这种情况(最有可能的方法是将所有东西都迁移到UUID),那么我强烈建议你这样做,我计划一有时间就这么做。
除了警告之外,迁移active_storage_attachments表以将record_id列更改为text确实有效。我不得不调整我们应用程序中的几个位置,我们使用record_id将值转换为连接中的文本。例如,我在加入一个具有UUID ID的模型时使用了以下代码。

.joins("
         LEFT OUTER JOIN active_storage_attachments
         ON active_storage_attachments.record_id = documents.id::text
       ")

希望这可以帮助那些陷入困境的人,因为并非所有使用模型的ActiveStorage都使用UUID或bigint ID。

daupos2t

daupos2t3#

我也有这个问题。我的模型都使用UUID。由于ActiveStorage中没有需要保留的记录,我删除并重新创建了:active_storage_attachments:active_storage_blobs表。这是我的迁移,如果它对任何人都有用。使用Rails 6.0.4。

def change
  reversible do |dir|
    dir.up do
      drop_table :active_storage_attachments
      drop_table :active_storage_blobs
      drop_table :active_storage_variant_records

      create_table "active_storage_blobs", id: :uuid,
        default: -> { "gen_random_uuid()" }, force: :cascade do |t|

        t.string   :key,        null: false
        t.string   :filename,   null: false
        t.string   :content_type
        t.text     :metadata
        t.bigint   :byte_size,  null: false
        t.string   :checksum,   null: false
        t.datetime :created_at, null: false
        t.index [ :key ], unique: true
      end

      create_table "active_storage_attachments", id: :uuid,
        default: -> { "gen_random_uuid()" }, force: :cascade do |t|

        t.string     :name,     null: false
        t.references :record,   null: false, polymorphic: true, index: false, type: :uuid
        t.references :blob,     null: false, type: :uuid
        t.datetime :created_at, null: false
        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
    end

      create_table :active_storage_variant_records, id: :uuid,
       default: -> { "gen_random_uuid()" }, force: :cascade do |t|
        t.belongs_to :blob, null: false, index: false, type: :uuid
        t.string :variation_digest, null: false

        t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
        t.foreign_key :active_storage_blobs, column: :blob_id, type: :uuid
   end

    dir.down do
      drop_table :active_storage_attachments
      drop_table :active_storage_blobs
      drop_table :active_storage_variant_records

      # original tables generated by rails
      create_table :active_storage_blobs do |t|
        t.string   :key,        null: false
        t.string   :filename,   null: false
        t.string   :content_type
        t.text     :metadata
        t.bigint   :byte_size,  null: false
        t.string   :checksum,   null: false
        t.datetime :created_at, null: false
        t.index [ :key ], unique: true
      end

      create_table :active_storage_attachments do |t|
        t.string     :name,     null: false
        t.references :record,   null: false, polymorphic: true, index: false
        t.references :blob,     null: false
        t.datetime :created_at, null: false
        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
    end
  end
end

相关问题