【问题标题】:Rails 4, double-nested models and strong parametersRails 4、双嵌套模型和强参数
【发布时间】:2013-10-29 13:38:39
【问题描述】:

我对 Ruby on Rails 还很陌生,并立即开始使用 rails 4。

我已成功嵌套了一个食谱和一个成分模型,以便可以以相同的形式添加它们。接下来,我想将数量嵌套在成分中,以便也可以在同一表格中添加。直到即将将成分的数量插入数据库之前,一切似乎都运行良好,因此我相信 recipes_controller 中的强参数有问题。但我会在下面发布完整的代码。 我正在为表单使用 simple_form。

感谢您的帮助!

这是我的模型:

class Recipe < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  has_many :ingredients, dependent: :destroy
  accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
  validates :title, presence: true
  validates :desc, presence: true
end


class Ingredient < ActiveRecord::Base
  belongs_to :recipe
  has_many :quantities, dependent: :destroy
  accepts_nested_attributes_for :quantities, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end

class Quantity < ActiveRecord::Base
  belongs_to :ingredient
end

这里是 recipes_controller

class RecipesController < ApplicationController

  def new
    @recipe = Recipe.new
    3.times do 
      ingredient = @recipe.ingredients.build
      1.times {ingredient.quantities.build }
    end
  end

  def create
    @recipe = Recipe.new(params[:recipe].permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]]))

    if @recipe.save
      redirect_to @recipe
    else
      render "new"
    end
  end

  def show
    @recipe = Recipe.find(params[:id])
  end


  def edit
    @recipe = Recipe.find(params[:id])
  end


  def update
    @recipe = Recipe.find(params[:id])

    if @recipe.update(params[:recipe].permit(:title, :desc))
      redirect_to @recipe
    else
      render 'edit'
    end
  end


  def destroy
    @recipe = Recipe.find(params[:id])
    @recipe.destroy

    redirect_to recipes_path
  end





  def index
    @recipes = Recipe.all
  end

  private
    def post_params
      params.require(:recipe).permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]])
    end
end

然后我使用简单的表格通过部分创建配方、成分和数量的表格。

_form:

<%= simple_form_for @recipe do |f| %>
    <%= f.error_notification %>


    <%= f.input :title %>
    <%= f.input :desc %>



    <%= f.simple_fields_for :ingredients do |builder| %>

    <%= render "ingredient_fields", :f => builder %>


    <% end %>

    <p class="links">
    <%= link_to_add_association 'add ingredient', f, :ingredients %>
    <p class="links">
    <%= f.error :base%>
    <%= f.submit %>

<% end %>

从 _ingredients_fields 渲染:

<div class="nested-fields">
    <%= f.input :name, label: "Ingredient" %>



    <%= f.simple_fields_for :quantities do |builder| %>

    <%= render "quantities_fields", :f => builder %>

    <% end %>

    <%= link_to_remove_association "remove", f %>
</div>

从 _quantities_fields 渲染:[EDITED]

<div class="nested-fields">
    <%= f.input :amount %>
    <%= f.input :unit %>
</div>

尝试添加新配方会导致以下日志语句:

Started POST "/recipes" for 127.0.0.1 at 2013-10-29 14:15:40 +0100
Processing by RecipesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"t6LKgDLwAxaU9xo2ipyCM+j1yfVF9WrI8AoGTX+gRkw=", "recipe"=>{"title"=>"Pancakes", "desc"=>"Tasty", "ingredients_attributes"=>{"0"=>{"name"=>"Milk", "quantities_attributes"=>{"0"=>{"amount"=>"1", "unit"=>"Cup"}}, "_destroy"=>"false"}}}, "commit"=>"Create Recipe"}
  [1m[35m (0.1ms)[0m  begin transaction
  [1m[36mSQL (3.5ms)[0m  [1mINSERT INTO "recipes" ("created_at", "desc", "title", "updated_at") VALUES (?, ?, ?, ?)[0m  [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["desc", "Tasty"], ["title", "Pancakes"], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
  [1m[35mSQL (0.4ms)[0m  INSERT INTO "ingredients" ("created_at", "name", "recipe_id", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["name", "Milk"], ["recipe_id", 27], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
  [1m[36m (7.8ms)[0m  [1mcommit transaction[0m
Redirected to http://www.projectcookbook.dev/recipes/27
Completed 302 Found in 22ms (ActiveRecord: 11.7ms)

【问题讨论】:

标签: ruby-on-rails ruby-on-rails-4 simple-form nested-forms strong-parameters


【解决方案1】:

您对 _quantities 和 _ingredients 部分使用了类似的渲染,这是错误的。在 _quantities_field 你不需要

<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>

AND 应该调整

<%= f.input :name, label: "Quantity" %>

在 _quantities_fields 中。

UPD

我认为问题出在成分模型的:reject_if-clause 中。它应该是

:reject_if => lambda { |a| a[:amount].blank? }

bc 在这里您指定数量的条件,而不是成分的条件

关于代码样式: 1) 在控制器中,最好使用私有方法的相关名称作为强参数:recipe_params 而不是post_params,然后用它来创建新的Recipe @recipe = Recipe.new(recipe_params)

2) 如果两个配方使用相似的配方,则配方、成分和数量之间的当前关联将导致成分重复。原因是belongs_to,它定义了单一关联。尝试另一种方法(如下)。

顺便说一句。最近我已经回答了类似的问题。看看吧:How do I reference an existing instance of a model in a nested Rails form?

【讨论】:

  • 对不起,我的错,我在我的问题中写错了代码,错误地从 _ingredient_fields 复制了相同的代码。我现在编辑了这个并编写了我一直在使用的真实代码。所以这不是导致问题的原因。
  • 另外,我注意到在您推荐的上一个问题中,他在模型之间使用了稍微不同的结构,通过数量连接配方和成分。但我不认为这是导致我的问题的原因还是它?感谢您的帮助!
  • 是的,问题出在成分模型上,而不是形式上
【解决方案2】:

我觉得你在这部分缺少了

&lt;%= simple_form_for @recipe do |f| %&gt;

应该是

&lt;%= simple_nested_form_for @recipe do |f| %&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-08
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多