如何实现更新控制器方法

时间:2015-11-07 06:37:38

标签: ruby-on-rails params

我正在使用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

3 个答案:

答案 0 :(得分:1)

有两个问题:

  1. 您需要保存更新的对象
  2. 资源的范围内执行此操作(虽然不是必需的)
  3. Resourceful

    第一步是确保您使用正确的路线等。

    您的控制器中不应该使用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>

    enter image description here

    这是建立在&#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