【问题标题】:Rails 5.2 ActiveStorage with UUIDs on Postgresql在 Postgresql 中使用 UUID 的 Rails 5.2 活动存储
【发布时间】:2019-01-03 00:19:17
【问题描述】:

我们的应用程序在 Postgresql 数据库上使用 uuid 作为主键。 (标准设置描述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"> 

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

【问题讨论】:

    标签: ruby-on-rails postgresql uuid rails-activestorage


    【解决方案1】:

    在活动存储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。这就是我们出错的地方。

    活动存储期望我们的消息模型使用整数外键,我们希望它使用 uuid。因此我们必须修复迁移,使用 uuid 而不是整数外键。 p>

    解决方案:

    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
    

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

    【讨论】:

    • 你好阿努拉格。我有同样的问题。问题是我有一个使用整数作为 id 的模型,还有一个使用 uuid 作为 id 的模型。两种型号均附有文件。所以主动存储不可能同时管理active_storage_attachments中record_id字段中的两种类型。这是一个糟糕的 Active Storage 限制。我现在需要将我的 2 个 id 模型转换为 uuid。
    • 我们有一个带有has_one attachment 的文档模型,并使用它通过foreign_key 将任何文档附加到不同的模型,而不是在模型中添加附件。通过这种方式,我们将损坏限制在一个模型上,并且效果很好。虽然,我对替代实现持开放态度。告诉我。
    • 感谢您的回答。事实上,我有 2 个带有 has_one_attachment(图像和照片)的模型,我不想合并它们,因为它们不拥有相同的字段。好吧,这不是问题,最后我将两者的ID类型都更改为UUID,只需将active_storage_attachments中的record_it类型更改为UUID。
    • 如果您已经应用了默认迁移,here are some migrations 您可以在事后申请修复您的附件表。
    • 你的救命稻草
    【解决方案2】:

    我迟到了 2020 年的聚会,但正如 anurag 所提到的,这是由于 active_storage_attachments DB 表为 record_id 使用了 bigint。我无法迁移所有带有 ActiveStorage 附件的模型以使用 UUID,因此我需要一种同时支持 UUID 和 bigint 的方法。

    警告:如果您可以避免这种情况(通过最有可能将所有内容迁移到 UUID),那么我强烈建议您这样做,并且我计划一有时间就这样做。

    除了警告之外,迁移 active_storage_attachments 表以将 record_id 列更改为 text 确实有效。我不得不调整我们的应用程序中我们加入到 active_storage_attachments 表的几个地方,使用 record_id 将值转换为加入中的文本。例如,我在加入具有 UUID ID 的模型时使用了以下代码。

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

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

    【讨论】:

      【解决方案3】:

      我也有这个问题。我的模型都使用 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
      
            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
      
          dir.down do
            drop_table :active_storage_attachments
            drop_table :active_storage_blobs
      
            # 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
      

      【讨论】:

        猜你喜欢
        • 2018-09-23
        • 1970-01-01
        • 2018-10-22
        • 1970-01-01
        • 2018-12-25
        • 2014-09-13
        • 2018-11-18
        • 2018-11-07
        • 2019-06-06
        相关资源
        最近更新 更多