使用Cacoon

时间:2017-01-23 21:24:46

标签: ruby-on-rails nested-forms nested-attributes strong-parameters

我一直在尝试构建一个相当复杂的食谱对象,它应该有不确定数量的成分("通心粉","奶酪","黄油")和方向("煮面条","添加奶酪")。

配方表单对象是使用Cacoon gem构建的,允许用户添加嵌套的成分/方向值。我已在控制器中定义了strong_params,并且这些参数已成功发送到create / update RecipesController操作;但是控制器仍在回滚提交。

我遗忘的任何线索?

注意

如果我保存配方而不包含任何嵌套属性,则配方会成功创建,然后我可以编辑/更新配方并添加嵌套属性。所以它只是抱怨创建动作 ......

这是相关的控制台输出:

Processing by RecipesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"[token removed for brevity]", "recipe"=>{"name"=>"French bread", "cuisine_id"=>"2", "ingredients_attributes"=>{"0"=>{"quantity"=>"500", "measure"=>"grams", "item"=>"flour", "_destroy"=>"false"}, "1"=>{"quantity"=>"250", "measure"=>"ml", "item"=>"water", "_destroy"=>"false"}, "2"=>{"quantity"=>"10", "measure"=>"grams ", "item"=>"yeast", "_destroy"=>"false"}}, "directions_attributes"=>{"0"=>{"direction"=>"Knead dough", "_destroy"=>"false"}, "1"=>{"direction"=>"Let rise 2 hours", "_destroy"=>"false"}, "2"=>{"direction"=>"Bake in 500 degree oven for 30 min.", "_destroy"=>"false"}}}, "button"=>""}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 1], ["LIMIT", 1]]
   (0.1ms)  begin transaction
  Cuisine Load (0.1ms)  SELECT  "cuisines".* FROM "cuisines" WHERE "cuisines"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   (0.1ms)  rollback transaction

recipe.rb

    class Recipe < ApplicationRecord
     belongs_to :user
     belongs_to :cuisine

     has_many :ingredients, dependent: :destroy
     has_many :directions, dependent: :destroy
     validates :name, presence: true


     accepts_nested_attributes_for :ingredients,
                                  reject_if: :all_blank,
                                  allow_destroy: true

     accepts_nested_attributes_for :directions,
                                  reject_if: :all_blank,
                                  allow_destroy: true
   end

recipes_controller.rb

    class RecipesController < ApplicationController
      before_action :verify_user
      before_action :set_recipe, only: [:show, :edit, :update, :destroy]

      [...]

      def new
        @recipe = current_user.recipes.build
      end

      def create
        @recipe = current_user.recipes.build(recipe_params)

        if @recipe.save
         redirect_to @recipe, notice: "Recipe added!"
        else
         flash.now[:alert] = "There was a problem saving the recipe. Please try again."
         render :new
        end
      end

      [...]

    private

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

    def recipe_params
      params.require(:recipe).permit(:name, :cuisine_id,
                                   ingredients_attributes: [:quantity, :measure, :item, :_destroy],
                                   directions_attributes: [:direction, :_destroy])
     end
    end

_form.html.erb

<%= form_for recipe, html: { multipart: true } do |f| %>
  <div class="form-group">
    <%= f.label :name %>
    <%= f.text_field :name, placeholder: 'Recipe name', class: "form-control" %>
  </div>
  <div class="form-group">
    <%= f.label :cuisine_id %><br>
    <%= f.select(:cuisine_id, options_from_collection_for_select(Cuisine::all, :id, :name),
    {:prompt => 'Please Choose'}, :class => "form-control") %>
  </div>

    <div class="col-md-8">
      <div class="form-group">
        <h3>Ingredients</h3>
          <%= f.fields_for :ingredients do |ingredient| %>
            <%= render 'ingredient_fields', f: ingredient %>
          <% end %>
        <div class="links">
          <%= link_to_add_association 'Add Ingredient', f, :ingredients, class: "form-button btn btn-default" %>
        </div>
      </div>
    </div>

    <div class="col-md-4">
      <div class="form-group">
        <h3>Directions</h3>
        <%= f.fields_for :directions do |direction| %>
          <%= render 'direction_fields', f: direction %>
        <% end %>
        <div class="links">
          <%= link_to_add_association 'Add Direction', f, :directions, class: "form-button btn btn-default" %>
        </div>
      </div>
    </div>
    <div class="form-inline clearfix col-md-12">
      <%= f.button :submit, class: "form-button btn btn-success" %>
      <%= link_to "Back", url_for(:back), class: "form-button btn btn-default" %>
    </div>
<% end %>

_ingredient_fields.html.erb

<div class="form-inline clearfix">
  <div class="nested-fields">
    <%= f.number_field :quantity, placeholder: 'qnt', class: "form-control" %>
    <%= f.text_field :measure, placeholder: 'measure', class: "form-control" %>
    <%= f.text_field :item, placeholder: 'ingredient', class: "form-control" %>
    <%= link_to_remove_association "Remove", f, class: "form-button btn btn-default" %>
    </div>
  </div>

_direction_fields.html.erb

<div class="form-inline clearfix">
  <div class="nested-fields">
    <%= f.text_area :direction, placeholder: 'Direction', class: "form-control" %>
    <%= link_to_remove_association "Remove", f, class: "btn btn-default form-button" %>
  </div>
</div>

2 个答案:

答案 0 :(得分:0)

尝试将:id放在嵌套模型的参数括号中,如此

user.teams

答案 1 :(得分:0)

所以问题是Rails 5的一个错误,与belongs_to_required_by_default方法设置为false有关。这解释了为什么可以使用嵌套属性更新记录但不能创建记录。您可以通过完全禁用父对象验证或在parent_model.rb文件中包含inverse_of: :parent_model_name来解决此问题。

有关问题here

的更多信息