首页 文章

Rails 5.2使用Cocoon表单的Active Storage

提问于
浏览
2

我想使用带有Active Storage的动态cocoon表单将一些图像保存到模型中以处理文件 .

我有一个农民班,有很多苹果,农民可以通过农民形式为每种不同类型的苹果添加多个图像 .

class Farmer < ActiveRecord::Base
  has_many :apples, inverse_of: :farmer
  accepts_nested_attributes_for :apples, allow_destroy: true,
                                reject_if: :all_blank
end

class Apple < ActiveRecord::Base
  has_many_attached :apple_images
end

在农民控制器里面我有:

class Farmer < ApplicationController


  def update
    @farmer = Farmer.find(params[:farmer_id])

    if @farmer.valid?
      @farmer.update!(farmer_params)
      redirect_to edit_farmer_path(farmer_id: @farmer.id)
    else
      ...
      ...
    end
  end

  private
  def farmer_params
    params.require(:farmer).permit(
      :farmer_name,
      apples_attributes: [
        :id,
        :color,
        :size,
        :_destroy
      ])
  end
end

我的观点我刚把它添加到我的茧领域

<div class="form-field">
  <%= f.label :apple_images, "Please upload apple images" %>
  <%= f.file_field :apple_images, multiple: true, data: { validates: {required: {}} } %>
</div>

现在,一旦保存了农民对象,cocoon将使用 accepts_nested_attributes_for 调用保存apple属性 . 这一切都正常,直到我尝试将 apple_images 添加到表单 .

阅读Active Storage自述文件,我看到它建议你应该在项目保存后立即附加文件 .

你可以阅读readme here

但简而言之,如果您想在控制器中使用单个图像,请执行以下操作:

#inside an update method
Current.user.avatar.attach(params.require(:avatar))

或者如果你想要多个图像:

def create
  message = Message.create! params.require(:message).permit(:title, :content)
  message.images.attach(params[:message][:images])
  redirect_to message
end

当图像直接在我在控制器中保存的模型上时,这看起来相当简单 .

起初,我认为这可能就像向params添加apple_images一样简单:

def farmer_params
    params.require(:farmer).permit(
      :farmer_name,
      apples_attributes: [
        :id,
        :color,
        :size,
        :apple_images,
        :_destroy
      ])
  end

但这会返回一个错误:

ActiveModel::UnknownAttributeError - unknown attribute 'apple_images' for Apple.:

我正在考虑在苹果模型上使用after_save回调来在更新/创建苹果对象后附加图像 . 虽然我不知道如何实现这一目标 .

感到有些失落,任何想法或建议将不胜感激

编辑

这是更新时params的样子:

<ActionController::Parameters {"utf8"=>"✓", "_method"=>"patch",
   "farmer"=>{"farmer_name"=>"billy the farmer", "apples_attributes"=>
     {"0"=>{"color"=>"Green", 
            "size"=>"A", 
            "apple_images"=>[#<ActionDispatch::Http::UploadedFile:0x007f9e8aa93168 @tempfile=#<Tempfile:/var/folders/n7/65r5561n44q0w4bdnmw42l880000gn/T/RackMultipart20171211-87415-1m2w7gh.png>, @original_filename="Screen Shot 2017-12-07 at 09.13.28.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"farmer[apples_attributes][0][apple_images][]\"; filename=\"Screen Shot 2017-12-07 at 09.13.28.png\"\r\nContent-Type: image/png\r\n">, 
                             #<ActionDispatch::Http::UploadedFile:0x007f9e8aa93118 @tempfile=#<Tempfile:/var/folders/n7/65r5561n44q0w4bdnmw42l880000gn/T/RackMultipart20171211-87415-1gdbax2.jpeg>, @original_filename="WhatsApp Image 2017-12-06 at 1.23.35 PM.jpeg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"farmer[apples_attributes][0][apple_images][]\"; filename=\"WhatsApp Image 2017-12-06 at 1.23.35 PM.jpeg\"\r\nContent-Type: image/jpeg\r\n">], 
      "_destroy"=>"false", "id"=>"4"}}}, 
     "commit"=>"Next", 
     "controller"=>"farmer/produce", 
     "action"=>"update", 
     "farmer_id"=>"3"} permitted: false>

2 回答

  • 3

    您应该从 farmer_params 中删除 apple_images (因为它不是 Apple 的已知属性) . 但删除它将确保图像不被保存 . 然而,这是如何工作的(有点奇怪的imho) .

    如果您检查文档,他们会明确忽略 images 属性并单独设置它:

    message = Message.create! params.require(:message).permit(:title, :content)
    message.images.attach(params[:message][:images])
    

    我不完全确定你应该如何在嵌套表单设置中解决这个问题 . 您可以迭代参数中的所有苹果并尝试设置 apple_images 但这似乎非常容易出错(如何将没有id的新苹果与保存的苹果相匹配?) .

    您可以尝试添加如下方法(并将 apple_images 保留在允许的参数中):

    def apple_images=(images)
      self.apple_images.attach(images)
    end
    

    但不确定在保存 apple 之前是否有效 .

  • 1

    添加 apple_images 作为具有空数组的哈希的键,如下所示:

    params.require(:farmer).permit(
      :farmer_name,
      { apple_images: [] },
      apples_attributes: [
        :id,
        :color,
        :size,
        :_destroy
      ])
    

    这是因为当您一次上传多个图像时,它们将作为数组以params形式发送 .

相关问题