Rails Active Storage 可以映射到数据库中预先存在的图像 table 吗?

Can Rails Active Storage map to a pre-existing Images table in the database?

我正在开发旧版 Rails 应用程序,最近升级到 Rails 5.2。它已经有一个带有上传功能的自定义图像实现,并且数据库中已经有数百万张图像。 Image型号belongs_to其他型号;他们每个人要么 has_many :images 要么 has_one :image.

这是图片的架构 table:

  create_table "images", id: :integer, unsigned: true, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string "content_type", limit: 100
    t.integer "user_id"
    t.date "when"
    t.text "notes"
    t.string "copyright_holder", limit: 100
    t.integer "license_id", default: 1, null: false
    t.integer "num_views", default: 0, null: false
    t.datetime "last_view"
    t.integer "width"
    t.integer "height"
    t.float "vote_cache"
    t.boolean "ok_for_export", default: true, null: false
    t.string "original_name", limit: 120, default: ""
    t.boolean "transferred", default: false, null: false
    t.boolean "gps_stripped", default: false, null: false
  end

部分实施是 ImageImage::Url 的子 class,它根据大小获取图像的 URL(在 AWS 上)请求,ImageMagick 已经生成的各种尺寸。

class Image
  class Url
    SUBDIRECTORIES = {
      full_size: "orig",
      huge: "1280",
      large: "960",
      medium: "640",
      small: "320",
      thumbnail: "thumb"
    }.freeze

    SUBDIRECTORY_TO_SIZE = {
      "orig" => :full_size,
      "1280" => :huge,
      "960" => :large,
      "640" => :medium,
      "320" => :small,
      "thumb" => :thumbnail
    }.freeze

    attr_accessor :size, :id, :transferred, :extension

    def initialize(args)
      size = args[:size]
      size = SUBDIRECTORY_TO_SIZE[size] unless size.is_a?(Symbol)
      size = :full_size if size == :original
      self.size        = size
      self.id          = args[:id]
      self.transferred = args[:transferred]
      self.extension   = args[:extension]
    end

    def url
      for source in source_order
        return source_url(source) if source_exists?(source)
      end
      source_url(fallback_source)
    end

    def source_exists?(source)
      spec = format_spec(source, :test)
      case spec
      when :transferred_flag
        transferred
      when /^file:/
        local_file_exists?(spec)
      when /^http:/
        remote_file_exists?(spec)
      when /^https:/
        remote_file_exists?(spec)
      else
        raise("Invalid image source test spec for "\
              "#{source.inspect}: #{spec.inspect}")
      end
    end

    def local_file_exists?(spec)
      File.exist?(file_name(spec)[7..])
    end

    def remote_file_exists?(spec)
      url = URI.parse(file_name(spec))
      result = Net::HTTP.new(url.host, url.port).request_head(url.path)
      result.code == 200
    end

    def source_url(source)
      file_name(format_spec(source, :read))
    end

    def file_name(path)
      "#{path}/#{subdirectory}/#{id}.#{extension}"
    end

    def subdirectory
      SUBDIRECTORIES[size] || raise("Invalid size: #{size.inspect}")
    end

    def source_order
      OurApp.image_precedence[size] || OurApp.image_precedence[:default]
    end

    def fallback_source
      OurApp.image_fallback_source
    end

    def format_spec(source, mode)
      spec = specs(source)[mode]
      spec.is_a?(String) ? format(spec, root: OurApp.root) : spec
    end

    def specs(source)
      OurApp.image_sources[source] ||
        raise("Missing image source: #{source.inspect}")
    end
  end
end

所以我正在考虑我们现有的数据 table 是否可以以某种方式迁移以与 Active Storage(未安装在此 Rails 应用程序上)一起使用。

EDIT 上面class提出的一个问题,我没写,是不是我们建立的图像URL结构将与 Active Storage 兼容。即使实际源 url 信息已迁移到 blob,此“url 生成器”是否仍能正常工作?可能我不了解 AWS 存储的工作原理,也许没有真正的“来源”url.

我找到的所有教程和解释器都讨论了在新的 Rails 应用程序上安装 Active Storage,或使用它向现有模型添加附件。那不是我的情况——我已经有一个与其他十几个模型相关的图像模型,并且他们已经知道他们的“附件”,即图像关系,是什么。

我的问题是,Active Storage 能否以某种方式利用现有图像 table 及其关系——或者 Active Storage 是否更恰当地理解为这个自己动手的设置,无法与之集成。

关于“Rails 没有模型的 Active Storage”,这似乎暗示 Active Storage 和模型之间的映射可以发生。我不明白的是 Active Storage 和现有图像模型之间的关系。据我所知,图像模型 has_one_attachedhas_many_attached (因为用户或产品会有附件)是没有意义的 - 它已经是附件本身的模型。还是我理解错了?

ActiveStorage 的核心实际上是三个 table(和模型),它们在某种程度上对应于您的图像 table:

class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    # Use Active Record's configured type for primary and foreign keys
    primary_key_type, foreign_key_type = primary_and_foreign_key_types

    create_table :active_storage_blobs, id: primary_key_type do |t|
      t.string   :key,          null: false
      t.string   :filename,     null: false
      t.string   :content_type
      t.text     :metadata
      t.string   :service_name, null: false
      t.bigint   :byte_size,    null: false
      t.string   :checksum,     null: false

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

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

    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

    create_table :active_storage_variant_records, id: primary_key_type do |t|
      t.belongs_to :blob, null: false, index: false, type: foreign_key_type
      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
    end
  end

  private
    def primary_and_foreign_key_types
      config = Rails.configuration.generators
      setting = config.options[config.orm][:primary_key_type]
      primary_key_type = setting || :primary_key
      foreign_key_type = setting || :bigint
      [primary_key_type, foreign_key_type]
    end
end

正如您从迁移中看到的那样,它使用 active_storage_blobs 来存储有关所存储文件的实际信息。一个 blob 也可以有多个变体。

active_storage_attachments 通过多态关联将 blob 与资源(附加附件的模型)连接起来。这使您可以将 has_one_attached/has_many_attached 添加到应用程序中的任何模型,而无需添加任何其他数据库列或 table。

So I'm considering whether Active Storage (which is not installed on this Rails app) could work with this existing setup.

让我们这样说吧——您不应该期望您可以将遗留数据即插即用到 ActiveStorage 中。它是一款非常有主见的软件,主要围绕能够以最少的配置插入任意数量的模型这一目标而设计。

ActiveStorage 可能与您现有的设置协同工作(将其替换为新记录),但是用 AS 替换遗留代码很可能需要一些繁重的数据迁移,您还需要很好地理解如何AS 作品。

What i don't understand is the relationship betwen Active Storage and an existing Image model.

那是因为真的有 none。 ActiveSupport::AttachmentActiveSupport::Blob 对您的 Rails 应用程序中具有附件的所有模型起到相同的作用。它在设计时并未考虑到遗留支持。