神殿与Rails多个多态图像上传

时间:2017-01-24 14:18:24

标签: image-uploading ruby-on-rails-5 shrine

我一直在努力了解大约5个小时,试图理解为什么Shrine阻止我的上传。我要么得到像“Shrine:Invalid file”这样的错误,要么在强大的参数中得到“Expected Array but got string”。如果没有错误,则实际上不保存图像。

require "image_processing/mini_magick"

class ImageUploader < Shrine
  include ImageProcessing::MiniMagick

  plugin :activerecord
  plugin :backgrounding
  plugin :cached_attachment_data
  plugin :determine_mime_type
  plugin :delete_raw
  plugin :direct_upload
  plugin :logging, logger: Rails.logger
  plugin :processing
  plugin :remove_attachment
  plugin :store_dimensions
  plugin :validation_helpers
  plugin :versions

  Attacher.validate do
    validate_max_size 2.megabytes, message: 'is too large (max is 2 MB)'
    validate_mime_type_inclusion ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']
  end

  def process(io, context)
    case context[:phase]
    when :store
      thumb = resize_to_limit!(io.download, 200, 200)
      { original: io, thumb: thumb }
    end
  end
end
class Image < ActiveRecord::Base
  include ImageUploader[:image]
  belongs_to :imageable, polymorphic: true
end
class Product < ApplicationRecord

  has_many :images, as: :imageable, dependent: :destroy    
  accepts_nested_attributes_for :images, allow_destroy: true
...
# Strong Params: 

def product_params
  params.require(:product).permit(
    :name, :brand_id, :category_id, :price, :compare_price, :description,
    images_attributes: { image: [] },
    product_properties_attributes: [:id, :property_id, :value]
  )
...

我的观点:

  <%= f.fields_for :images do |image_form| %>
    <%= image_form.file_field :image, multiple: true %>
  <% end %>

根据我在文档或gorails上阅读的所有内容,这应该有效。我是否需要重构images_attributes哈希?我也尝试过使用direct_uploads,但很难让presigned_url与S3一起工作。

Refile让这很容易,所以我可能会哭回来。

有什么我显然做错了吗?

1 个答案:

答案 0 :(得分:4)

根据fields_for documentation,将为project.images集合中的每个图像调用提供的块。因此,如果您的产品目前没有任何图像,则不会调用该块(根据文档)。

要使嵌套属性起作用,您需要在创建产品时转发以下参数:

product[images_attributes][0][image] = <file object or data hash>
product[images_attributes][1][image] = <file object or data hash>
product[images_attributes][2][image] = <file object or data hash>
...

如果您查看“Multiple Files”Shrine指南,建议您只有一个文件字段,可以接受多个文件:

<input type="file" name="file" multiple>

然后使用Uppy为此字段设置直接上传,为上传的文件数据哈希填充的每个上传文件动态生成image字段:

<input type="hidden" name="product[images_attributes][0][image]" value='{"id":"...","storage":"cache","metadata":{...}}'>
<input type="hidden" name="product[images_attributes][1][image]" value='{"id":"...","storage":"cache","metadata":{...}}'>
....

或者你可以让用户附加多个文件,这些文件都提交给应用程序,然后在控制器中对它们进行解构:

class ProductsController < ApplicationController
  def create
    images_attributes = params["files"].map { |file| {image: file} }
    Product.create(product_params.merge(images_attributes: images_attributes))
  end
end

在这种情况下,您必须确保您的HTML表单设置了enctype="multipart/form-data"属性(否则只会提交文件的文件名,而不是文件本身)。