Rails 5.2 Cocoon 形式的主动存储
Rails 5.2 Active Storage with Cocoon forms
我想使用带有 Active Storage 的动态茧形式将一些图像保存到模型中以处理文件。
我有一个农夫class,他有很多苹果,农夫可以通过农夫表格为每个不同种类的苹果添加多张图片。
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
但这会return一个错误:
ActiveModel::UnknownAttributeError - unknown attribute 'apple_images' for Apple.:
我正在考虑在 apple 模型上使用 after_save 回调来在更新/创建 apple 对象后附加图像。尽管我也不确定如何实现这一目标。
感觉有点迷茫,任何想法或建议将不胜感激
编辑
这是更新时参数的样子:
<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>
您应该从 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
之前是否有效。
将 apple_images
作为键添加到具有空数组的散列中,如下所示:
params.require(:farmer).permit(
:farmer_name,
{ apple_images: [] },
apples_attributes: [
:id,
:color,
:size,
:_destroy
])
这是因为当您一次上传多张图片时,它们会以数组的形式在参数中发送。
我想使用带有 Active Storage 的动态茧形式将一些图像保存到模型中以处理文件。
我有一个农夫class,他有很多苹果,农夫可以通过农夫表格为每个不同种类的苹果添加多张图片。
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
但这会return一个错误:
ActiveModel::UnknownAttributeError - unknown attribute 'apple_images' for Apple.:
我正在考虑在 apple 模型上使用 after_save 回调来在更新/创建 apple 对象后附加图像。尽管我也不确定如何实现这一目标。
感觉有点迷茫,任何想法或建议将不胜感激
编辑
这是更新时参数的样子:
<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>
您应该从 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
之前是否有效。
将 apple_images
作为键添加到具有空数组的散列中,如下所示:
params.require(:farmer).permit(
:farmer_name,
{ apple_images: [] },
apples_attributes: [
:id,
:color,
:size,
:_destroy
])
这是因为当您一次上传多张图片时,它们会以数组的形式在参数中发送。