【问题标题】:Rails 5.2 Active Storage with Cocoon formsRails 5.2 带有 Cocoon 表单的 Active Storage
【发布时间】:2017-12-11 11:53:50
【问题描述】:

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

我有一个农夫班,里面有很多苹果,农夫可以通过农夫表格为每个不同种类的苹果添加多张图片。

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

在我拥有的 Farmer Controller 内部:

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_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

当图像直接在我保存在控制器中的模型上时,这似乎相当简单。

起初,我认为这可能就像将 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 回调来附加图像。虽然我也不确定如何实现这一点。

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

编辑

这是更新时参数的样子:

 <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>

【问题讨论】:

  • 查看您的日志并查看实际通过哪些参数/字段名称...编辑您的问题并将它们添加到那里。
  • 嗨@TarynEast 我已经添加了参数。您会注意到apple images 将与其余的苹果参数一起移动,这些参数将通过农夫accepts_nested_attributes_for 保存。 ActiveStorage 希望将图像附加到保存后的对象上,我相信 ActiveStorage 设置了多态表。我想知道是否可以将苹果图像传递给苹果属性之外的 Apple 类,以便我们可以设置 after_save 回调来附加图像?

标签: ruby-on-rails-5 image-uploading cocoon-gem rails-activestorage


【解决方案1】:

您应该从farmer_params 中删除apple_images(因为它不是Apple 的已知属性)。但删除它会确保图像不会被保存。然而,这就是它的工作方式(有点奇怪恕我直言)。

如果您查看文档,他们会明确忽略 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 之前这是否有效。

【讨论】:

  • 感谢@nathanvda,我已将图片的上传从 cocoon 移至另一个步骤,以便我们可以直接将它们添加到对象中。我们发现 ActiveStorage 正在使用某种匿名多态表来保存图像,因此需要保存对象的实例以便我们可以访问 ID,因此您需要在一些 after_save 回调中执行此操作模型。我可以看到这个工作的唯一方法是,如果 Cocoon 可以访问对象以传递接受的嵌套属性的属性,然后以某种方式定义模型级回调?不过再次感谢!
  • 听起来很合理。坦率地说,我通常会这样做:只为现有项目添加附件(我是 dropzonejs 的忠实粉丝)。
【解决方案2】:

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

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

这是因为当您一次上传多张图片时,它们会在参数中作为数组发送。

【讨论】:

    猜你喜欢
    • 2018-11-22
    • 1970-01-01
    • 2019-11-01
    • 2019-01-01
    • 2018-09-05
    • 2023-03-07
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多