我正在使用ruby on rails进行Web应用程序开发。我想让用户上传他们喜欢的食物的图像。我有food_item模型和food_image模型。在food_item模型中:
has_many :food_images
has_many :food_portions #this is the work done by another teammate
我也在food_item控制器中定义:
def food_item_params
params.require(:food_items).permit(:name, :category, :description, food_images_attributes: [:id, :food_item_id, :avatar]).tap do |whitelisted|
whitelisted[:portion] = params[:food_items][:portion]
whitelisted[:price] = params[:food_items][:price]
end
答案 0 :(得分:1)
有两个问题:
第一步是确保您使用正确的路线等。
您的控制器中不应该使用add_images
方法 - 您可以通过edit
/ update
实现所需:
#config/routes.rb
resources :food_items do
resources :images #-> if necessary, this should be its own controller rather than adding needless methods to your other controller
end
您应该使用以下控制器设置:
#app/models/food_item.rb
class FoodItem < ActiveRecord::Base
accepts_nested_attributes_for :food_images
end
#app/controllers/food_items_controller.rb
class FoodItemsController < ApplicationController
def edit
@food_item = FoodItem.find params[:id]
@food_item.food_images.build
end
def update
@food_item = FootItem.find params[:id]
respond_to do |format|
if @food_item.update food_item_params
...
end
end
end
private
def food_item_params
params.require(:food_items).permit(:name, :category, :description, food_images_attributes: [:id, :food_item_id, :avatar]) #-> this is enough (no need to "whitelist")
end
end
这将使您能够加载以下内容:
#url.com/food_items/:id/edit
#app/views/food_items/edit.html.erb
<%= form_for @food_item do |f| %>
= form_for @food_item, html: { :multipart => true } do |f|
= f.label :title
= f.text_field :title
= f.fields_for :food_images do |p|
= p.label :avatar
= p.file_field :avatar
.actions
= f.submit
<% end %>
这将提交给&#34;更新&#34;方法,应该为您保存所需的对象。
您一次只能上传一个文件
如果您需要上传多个文件,则需要使用cocoon
之类的gem来添加它们。 Rails很棒,但并不神奇 - 它必须与每个fields_for
构建一个对象。
如果需要,我可以解释更多。
-
为了向您提供有关为什么应该使用edit
/ update
方法的背景信息,您需要查找资源丰富的原则以进行面向对象的编程。< / p>
这是建立在&#34;资源&#34;在inception of HTTP提出的原则 - 一套标准化的技术,允许浏览器从服务器发送和检索数据。
简而言之,这意味着您应该遵守某些conventions以保持您的应用可扩展性。
因为Ruby / Rails是object orientated,所以你在精心定制的应用程序中所做的一切都应该围绕对象。与资源一样,这些允许您创建一个灵活且可扩展的系统如果正确完成。
因此,使用您的代码,您必须记住,您正在尝试将添加图片添加到食品对象中。因此,你应该editing
食物项目对象,用额外的图像更新它;以上代码将帮助您实现。
答案 1 :(得分:0)
像Badheka说的那样:“你为什么要查询并保存@food_item?
无论如何,请注意,当您尝试创建food_images时,您确实:
food_item_params[:food_image]['avatar'].each do |a|
@food_image = @food_item.food_images.create!(:avatar=>a)
end
您在avatar
food_image
属性中循环显示food_item_params
但是,如果您检查food_item_params
,则有:
def food_item_params
params.require(:food_items).permit(food_images_attributes: [:id, :food_item_id, :avatar])
end
有了这个,在所有可能的情况下,这个参数预期的数据结构将是这样的:
{
food_items:
{
food_images_attributes:
{
id: "",
food_item_id: "",
avatar: ""
}
}
}
虽然food_item_params
返回的内容如下:
{
food_images_attributes:
{
id: "",
food_item_id: "",
avatar: ""
}
}
这有很多问题:
1)您收到的错误:param is missing or the value is empty: food_items
这表明进入的参数不是上面指定的格式。缺少父属性food_items
,因此这是您需要在发送头像的视图内部纠正的代码的第一部分,或者符合您的food_item_params
方法以满足结构通过参数进入的是什么。
2)没有food_item_params[:food_image]['avatar']
循环,因为你的参数中没有food_image
。您所拥有的是food_image_attributes
,因此您的循环将位于food_item_params[:food_image_attributes][:avatar]
3)循环food_item_params[:food_image_attributes][:avatar]
表明它是一个数组。如果是这样,那么你允许它的方式也是错误的。您必须在food_item_params
方法中指定它是一个数组,如下所示:
def food_item_params
params.require(:food_items).permit(food_images_attributes: [:id, :food_item_id, avatar: []])
end
但是,如果我怀疑,您的参数中的内容如下:
food_images_attributes:
{
id: "",
food_item_id: "",
avatar: []
}
然后您的food_item_params
方法应如下所示:
def food_item_params
params.require(:food_images_attributes).permit(:id, :food_item_id, avatar: [])
end
我会建议你查看你的参数并粘贴它的样子。
最后,检查您从视图中发送的内容,并相应地设置控制器,或检查您希望控制器期望的内容,并从视图中发送相同内容。
答案 2 :(得分:0)
您需要更改food_item_params方法:
来自:
def food_item_params
params.require(:food_items).permit(food_images_attributes: [:id, :food_item_id, :avatar])
end
致:
def food_item_params
params.require(:food_item).permit(food_images_attributes: [:id, :food_item_id, :avatar])
end
此外,您可以改进代码:
在food_item模型中添加accepts_nested_attributes_for:food_images,然后在控制器的方法中进行更改
def add_image
@food_item = FoodItem.find(params[:id])
respond_to do |format|
if @food_item.update_attributes(food_item_params)
format.html { redirect_to @food_item, notice: 'Images uploaded successfully' }
else
format.html { redirect_to add_image_food_item_path}
end
end
end