【问题标题】:Carrierwave gem. How to rename uploaded image versions after recreating them?载波宝石。重新创建后如何重命名上传的图像版本?
【发布时间】:2018-11-09 05:58:07
【问题描述】:

我有类似RailsCasts中描述的模型:

app/models/resident.rb:

class Resident < ActiveRecord::Base
  include PhotoConcern
end

app/models/employee.rb:

class Employee < ActiveRecord::Base
  include PhotoConcern
end

app/models/concerns/photo_concern.rb:

module PhotoConcern
  extend ActiveSupport::Concern

  included do
    mount_uploader :photo, PhotoUploader

    attr_accessor :photo_crop_x, :photo_crop_y, :photo_crop_w, :photo_crop_h

    after_save :crop_photo

    def crop_photo
      photo.recreate_versions! if photo_crop_x.present?
    end
  end
end

app/uploaders/photo_uploader.rb:

class PhotoUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :cropped do
    process :crop
  end

  version :thumb, from_version: :cropped do
    process resize_to_fill: [100, 100]
  end

  version :avatar, from_version: :cropped do
    process resize_to_fill: [200, 200]
  end

  def crop
    return if model.photo_crop_x.blank?

    resize_to_limit(500, nil)
    resize_to_fit(500, nil)

    manipulate! do |img|
      size = model.photo_crop_w << 'x' << model.photo_crop_h
      offset = '+' << model.photo_crop_x << '+' << model.photo_crop_y

      img.crop("#{size}#{offset}")
      img
    end
  end
end

app/views/employees/show.slim

= image_tag (@employee.photo.present? ? @employee.photo.url(:avatar) : "client_#{@employee.sex}.png"), class: 'img-circle img-responsive'

我想在裁剪后重命名版本文件,这样我的用户就不会为缓存而烦恼。 CarrierWave wiki 中描述了如何重命名文件以及 it's written“为了保存新生成的文件名,您必须在模型上调用 save! recreate_versions!”。

如何重命名版本文件?我不能再次在我的员工的after_save 中调用save!,因为有更多的钩子不应该被调用两次。此外,PhotoConcern 包含在另一个类中。

相关维基文章:

【问题讨论】:

    标签: ruby-on-rails carrierwave


    【解决方案1】:

    为了保存新生成的文件名,你必须调用 save!在 recreate_versions! 之后的模型上。

    所以我相信Carrierwave rubydocumentation中包含了对您的疑问的答案

    recreate_versions!(*versions) ⇒ Object

    重新创建版本并重新处理它们。如果它们的参数以某种方式发生了变化,这可用于重新创建版本。

    如果没有省略*versions,则此方法将存储,否则将存储cached file

    # File 'lib/carrierwave/uploader/versions.rb', line 216
    
    def recreate_versions!(*versions)
      # Some files could possibly not be stored on the local disk. This
      # doesn't play nicely with processing. Make sure that we're only
      # processing a cached file
      #
      # The call to store! will trigger the necessary callbacks to both
      # process this version and all sub-versions
      if versions.any?
        file = sanitized_file if !cached?
        # the file will be stored
        store_versions!(file, versions)
      else
        cache! if !cached?
        # If new_file is omitted, a previously cached file will be stored.
        store!
      end
    

    store! 是做什么的?

    这是the rubydoc page about store!

    store!(new_file = nil) ⇒ Object

    通过将文件传递到此 Uploader 的存储引擎来存储文件。 如果省略 new_file,则会存储之前缓存的文件

    此方法包含在您的class PhotoUploader &lt; CarrierWave::Uploader::Base 中,它使用with_callbacks 使用回调:store 来存储您的文件。回调触发该方法。

    # File 'lib/carrierwave/uploader/store.rb', line 53
    
    def store!(new_file=nil)
      cache!(new_file) if new_file && ((@cache_id != parent_cache_id) || @cache_id.nil?)
      if !cache_only and @file and @cache_id
        with_callbacks(:store, new_file) do
          new_file = storage.store!(@file)
          if delete_tmp_file_after_storage
            @file.delete unless move_to_store
            cache_storage.delete_dir!(cache_path(nil))
          end
          @file = new_file
          @cache_id = nil
        end
      end
    end
    

    store_versions! 方法有什么作用?

    def store_versions!(new_file, versions=nil)
      if versions
        active = Hash[active_versions]
        versions.each { |v| active[v].try(:store!, new_file) } unless active.empty?
      else
        active_versions.each { |name, v| v.store!(new_file) }
      end
    end
    

    什么是 Carrierwave 回调以及如何使用它们?

     after :store, :store_versions!
    

    关于SO explainswiki 的这个问题解释了回调的工作原理,通过在version :low do 块内执行after :store, :my_method,您将仅在after :store 回调上执行my_method(仅适用于该版本)。

    :store回调对应store!的执行。

    @filename 属性是什么? recreate_versions! 是如何对文件名进行编码的?

    @filename 是用lib/carrierwave/uploader/store.rb 中的filename 方法定义的

    ##
    # Override this in your Uploader to change the filename.
    #
    # Be careful using record ids as filenames. If the filename is stored in the database
    # the record id will be nil when the filename is set. Don't use record ids unless you
    # understand this limitation.
    #
    # Do not use the version_name in the filename, as it will prevent versions from being
    # loaded correctly.
    #
    # === Returns
    #
    # [String] a filename
    #
    def filename
      @filename
    end
    

    carrierwave 的指南建议在使用recreate_version! 重新创建版本时使用def filename 重新创建唯一的文件名。

    此方法不保存到数据库,保存到数据库需要在适当的Carrierwave回调上调用save!,而不破坏你CarrierwaveGEM

    我没有解决此问题的方法,但没有相关文档,我们应该开始构建它。

    【讨论】:

      【解决方案2】:

      对于那些希望在保存后更改上传的文件名并且您以某种方式重命名磁盘上的文件的人。您可以直接在数据库中更改记录而无需回调,然后重新加载活动记录。

      例如,

      photo.update_column(:attachment_file_name, "new_name.jpg")
      photo.reload
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-03
        • 1970-01-01
        • 2012-07-05
        • 1970-01-01
        • 2015-04-27
        • 1970-01-01
        • 1970-01-01
        • 2015-09-08
        相关资源
        最近更新 更多