代码之家  ›  专栏  ›  技术社区  ›  nimmolo

Rails活动存储能否映射到数据库中预先存在的图像表?

  •  1
  • nimmolo  · 技术社区  · 4 年前

    我正在开发一个旧版Rails应用程序,最近升级到Rails 5.2。它已经有了自己的图像上传实现,数据库中已经有数以百万计的图像。这个 Image 模型 belongs_to 其他型号;他们每个人都不是 has_many :images has_one :image .

    以下是图像表的模式:

      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
    

    实现的一部分是有一个子类 形象 , Image::Url ,它将根据请求的大小获取图像的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
    

    因此,我正在考虑是否可以以某种方式迁移现有的数据表,以使用活动存储(此Rails应用程序上未安装)。

    编辑 上述课程提出的一个问题(我没有写)是,我们建立的图像URL结构是否与活动存储兼容。即使实际的源url信息被迁移到BLOB,这个“url生成器”还能工作吗?我可能不了解AWS存储是如何工作的,也许没有真正的“源”url。

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

    我的问题是, 活动存储能否以某种方式利用现有的映像表 以及它之间的关系——或者说,主动存储更恰当地理解为一种替代您自己的设置,它无法与之集成。

    There is an SO question 关于“没有模型的Rails活动存储”,这似乎意味着活动存储和模型之间可能会发生映射。我不明白的是活动存储和现有映像模型之间的关系。据我所知,图像模型将 has_one_attached has_many_attached (就像用户或产品会有附件一样)-它已经是附件本身的一个模型。还是我弄错了?

    0 回复  |  直到 4 年前
        1
  •  2
  •   max Mike Williams    4 年前

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

    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 添加到应用程序中的任何模型,而无需添加任何其他数据库列或表。

    因此,我正在考虑活动存储(未安装在此Rails应用程序上)是否可以与此现有设置配合使用。

    让我们这样说吧——你不应该期望你可以直接将你的遗留数据插入到ActiveStorage中。这是一个非常固执己见的软件平台,主要围绕着能够以最少的配置插入任意数量的模型这一目标而设计。

    ActiveStorage很可能可以与您现有的设置一起正常工作(将其替换为新记录),但将旧代码替换为AS很可能需要一些繁重的数据迁移,您还需要非常好地了解AS的工作方式。

    我不明白的是活动存储和现有映像模型之间的关系。

    那是因为根本没有。 ActiveSupport::Attachment ActiveSupport::Blob 为Rails应用程序中具有附件的所有模型提供相同的角色。它的设计没有考虑到遗留支持。

    推荐文章