Ruby on Rails 4: Missing form field after commit - error is “Unpermitted parameter: ingredients_attributes”

二次信任 提交于 2020-01-06 13:11:51

问题


Question:

I'm working with cocoon gemfile & following the ERB style of it without haml/slim. I have my github here - The branch I'm working on is "cmodel" - Link.

The error is: Unpermitted parameter: ingredient_attributes

Really what I don't understand is just about everything about the models. I get pluralization is a thing. I get that strong parameters is a thing. My understanding to implement them is a bit fuzzy. I've found the rails guides & edge rails guides too simple for the expanded use here. I've flailed around with 80+ changes and feel like I've borked my install completely.

Some extras that I did:

  1. adding excessive accepts_attributes_for to blindly in models trying to guess issue
  2. I added a non-pluralized strong parameter to try and find out if this is the issue

  3. added ingredients to the quantities_attributes - blindly hoping this was it

  4. Removed all ingredient(s)_attribute(s)

  5. I have a weird schema now, put stuff into db probably shouldn't have

  6. Pulled the ingredients & quantities from permitted strong parameter list. Then added in quantities_attributes - with no issues. Then tried the same with ingredient(s)_attributes ... the issue still exists.

updated @ 08:29pm - 12/25/15:

Weird side effect ... 15 or 20 tests ago I noticed the 2nd field when you click the add ingredient link worked to add, but the 2nd column does not display when you click edit. Possibly related?

I guess in summary this should all work - it matches another example used by someone else & there's no reason it should fail according to an example.

The code is completely non-responsive to the pluralization in the strong parameters area - it's frustrating. I think my developing method is pretty borked at this point, going to take a break after 4 hours of this junk.

My console output for the current error: updated @ 08:29pm - 12/25/15

    Started PATCH "/recipes/1" for 68.54.21.200 at 2015-12-26 03:00:14 +0000
    Cannot render console from 68.54.21.200! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
    Processing by RecipesController#update as HTML
      Parameters: {"utf8"=>"✓", "authenticity_token"=>"OzJmuRuIMWVbJ1CpnCTyU52GhTEmrsOfiBiHACzIviN02MO48HBaZlX8JKvZvBXErqBfbXULnhcjT3gk2Zrh+A==", "recipe"=>{"title"=>"Recipe name", "description"=>"Recipe Description of Lindy's ...", "instruction"=>"Recipe Instruction", "quantities_attributes"=>{"0"=>{"amount"=>"8", "_destroy"=>"false", "id"=>"63"}, "1"=>{"amount"=>"9", "_destroy"=>"false", "id"=>"64"}, "1451098805028"=>{"amount"=>"11", "ingredient_attributes"=>{"name"=>"11"}, "_destroy"=>"false"}}}, "commit"=>"Update Recipe", "id"=>"1"}
      Recipe Load (0.2ms)  SELECT  "recipes".* FROM "recipes" WHERE "recipes"."id" = ? LIMIT 1  [["id", 1]]
    Unpermitted parameter: ingredient_attributes
       (0.1ms)  begin transaction
      Quantity Load (0.3ms)  SELECT "quantities".* FROM "quantities" WHERE "quantities"."recipe_id" = ? AND "quantities"."id" IN (63, 64)  [["recipe_id", "1"]]
      SQL (0.4ms)  INSERT INTO "quantities" ("amount", "recipe_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["amount", 11], ["recipe_id", "1"], ["created_at", "2015-12-26 03:00:14.818224"], ["updated_at", "2015-12-26 03:00:14.818224"]]
       (9.6ms)  commit transaction
    Redirected to https://cocoontest-mirv.c9users.io/recipes/1
    Completed 302 Found in 19ms (ActiveRecord: 10.7ms)

Setup

  • I ran the bundle install for the gemfile.
  • I made the entry in assests/application.js for the "//= require cocoon". It's been compiled and raked.
  • I setup a controller to view ingredient model directly and can add them manually through the ingredient page - but it never saves my ingredient via the Recipe model.

Models:

class Recipe < ActiveRecord::Base
  has_many :quantities
  has_many :ingredient,
           :through => :quantities
  accepts_nested_attributes_for :quantities,
           :allow_destroy => true
  accepts_nested_attributes_for :ingredient
end

class Quantity < ActiveRecord::Base
  belongs_to :recipe
  belongs_to :ingredient
  accepts_nested_attributes_for :ingredient
end

class Ingredient < ActiveRecord::Base
  has_many :quantities
  has_many :recipes, through: :quantities
  accepts_nested_attributes_for :quantities
end

Controller: updated @ 08:29pm - 12/25/15

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

  # GET /recipes
  # GET /recipes.json
  def index
    @recipes = Recipe.all
  end

  # GET /recipes/1
  # GET /recipes/1.json
  def show
    @recipe = Recipe.find(params[:id])

  end

  # GET /recipes/new
  def new
    @recipe = Recipe.new
  end

  # GET /recipes/1/edit
  def edit
        @recipe = Recipe.find(params[:id])
  end

  # POST /recipes
  # POST /recipes.json
  def create
    @recipe = Recipe.new(recipe_params)

    respond_to do |format|
      if @recipe.save
        format.html { redirect_to @recipe, notice: 'Recipe was successfully created.' }
        format.json { render :show, status: :created, location: @recipe }
      else
        format.html { render :new }
        format.json { render json: @recipe.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /recipes/1
  # PATCH/PUT /recipes/1.json
  def update
    respond_to do |format|
      if @recipe.update(recipe_params)
        format.html { redirect_to @recipe, notice: 'Recipe was successfully updated.' }
        format.json { render :show, status: :ok, location: @recipe }
      else
        format.html { render :edit }
        format.json { render json: @recipe.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /recipes/1
  # DELETE /recipes/1.json
  def destroy
    @recipe.destroy
    respond_to do |format|
      format.html { redirect_to recipes_url, notice: 'Recipe was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_recipe
      @recipe = Recipe.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def recipe_params
      #seems to work, but used wrong pluralization for quantity, should have been quantities_attributes
      params.require(:recipe).permit(:title, :description, :instruction, 
      :quantities_attributes => [:id, :ingredient, :ingredient_id, :recipe_id, :amount, :_destroy], 
      :ingredient_attributes => [:id, :_destroy, :ingredient_id, :name], 
      :ingredients_attributes => [:id, :_destroy, :ingredient_id, :name]
      )
    end
end

Here's the views ... portion from the github I linked above ...

edit.html.erb

<h1>Editing Recipe</h1>

    <%= render 'form' %>

    <%= link_to 'Show', @recipe %> |
    <%= link_to 'Back', recipes_path %>

_form.html.erb

<%= form_for @recipe, html: {class: "form-horizontal"} do |f| %>
  <% if @recipe.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@recipe.errors.count, "error") %> prohibited this recipe from being saved:</h2>

      <ul>
      <% @recipe.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <fieldset id="recipe-meta">
    <ol>
      <li class="control-group">
        <%= f.label :title, "Recipe Name", class: "control-label" %>
        <div class="controls"><%= f.text_field :title %></div>
      </li>
      <li class="control-group">
        <%= f.label :description, "A brief description of this recipe", class: "control-label" %>
        <div class="controls"><%= f.text_area :description, rows: 5 %></div>
      </li>
      <li class="control-group">
        <%= f.label :instruction, "Instructions for this recipe", class: "control-label" %>
        <div class="controls"><%= f.text_area :instruction, rows: 10 %></div>
      </li>
    </ol>
  </fieldset>

  <fieldset id="recipe-ingredients">
    <ol>
      <%= f.fields_for :quantities do |quantity| %>
        <%= render 'quantity_fields', f: quantity %>
      <% end %>
    </ol>
    <%= link_to_add_association 'add ingredient', f, :quantities, 'data-association-insertion-node' => "#recipe-ingredients ol", 'data-association-insertion-method' => "append", :wrap_object => Proc.new {|quantity| quantity.build_ingredient; quantity } %>
  </fieldset>
    <%= f.submit %>
  </div>
<% end %>

_quantity_fields.html.erb

<li class="control-group nested-fields">
  <div class="controls">
    <%= f.label :amount, "Amount:" %>
    <%= f.text_field :amount %>

    <%= f.fields_for :ingredient do |quantity_ingredient| %>
      <%= quantity_ingredient.text_field :name %>
    <% end %>

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

Schema

ActiveRecord::Schema.define(version: 20151206204139) do

  create_table "ingredients", force: :cascade do |t|
    t.text     "name"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.integer  "ingredient_id"
  end

  create_table "quantities", force: :cascade do |t|
    t.integer  "amount"
    t.text     "ingredient"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.string   "recipe_id"
    t.integer  "ingredient_id"
  end

  add_index "quantities", ["recipe_id"], name: "index_quantities_on_recipe_id"

  create_table "recipes", force: :cascade do |t|
    t.string   "title"
    t.text     "description"
    t.text     "instruction"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
    t.string   "recipe_id"
  end

  add_index "recipes", ["recipe_id"], name: "index_recipes_on_recipe_id"

end

Update: Including view source of edit page ... here's the html page resulting from project so far ...

<!DOCTYPE html>
<html>
<head>
  <title>Workspace</title>
  <link rel="stylesheet" media="all" href="/assets/ingredients.self-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css?body=1" data-turbolinks-track="true" />
<link rel="stylesheet" media="all" href="/assets/quantities.self-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css?body=1" data-turbolinks-track="true" />
<link rel="stylesheet" media="all" href="/assets/recipes.self-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css?body=1" data-turbolinks-track="true" />
<link rel="stylesheet" media="all" href="/assets/scaffolds.self-d2e5ccad1506299feea3a35bfb7c525e101bb3b214303715deb675fdc539948b.css?body=1" data-turbolinks-track="true" />
<link rel="stylesheet" media="all" href="/assets/application.self-e80e8f2318043e8af94dddc2adad5a4f09739a8ebb323b3ab31cd71d45fd9113.css?body=1" data-turbolinks-track="true" />
  <script src="/assets/jquery.self-a714331225dda820228db323939889f149aec0127aeb06255646b616ba1ca419.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/jquery_ujs.self-d456baa54c1fa6be2ec3711f0a72ddf7a5b2f34a6b4f515f33767d6207b7d4b3.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/turbolinks.self-c37727e9bd6b2735da5c311aa83fead54ed0be6cc8bd9a65309e9c5abe2cbfff.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/ingredients.self-877aef30ae1b040ab8a3aba4e3e309a11d7f2612f44dde450b5c157aa5f95c05.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/quantities.self-877aef30ae1b040ab8a3aba4e3e309a11d7f2612f44dde450b5c157aa5f95c05.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/recipes.self-877aef30ae1b040ab8a3aba4e3e309a11d7f2612f44dde450b5c157aa5f95c05.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/cocoon.self-05633fd25797688a657c08b26b8d4217031ee589f5ca76f0a57c11ac7d0e76ec.js?body=1" data-turbolinks-track="true"></script>
<script src="/assets/application.self-7862a8a8b42407b4741a1adeeea35f0d13ddc4f702ec532adb0674491d296495.js?body=1" data-turbolinks-track="true"></script>
  <meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="Yco8LpQtKNyieVhjN1HKDzyMMyMfVHJ+UpllUl7iR88uIJkvf9VD36yiLGFyyS2YD6rpf0zxL/b5zpp2q7AYFA==" />
</head>
<body>

<h1>Editing Recipe</h1>

<form class="form-horizontal" id="edit_recipe_2" action="/recipes/2" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="_method" value="patch" /><input type="hidden" name="authenticity_token" value="DxvtQX6V7LtVoez4faEXT5L/t2vOORoprujYH4IXqJFA8UhAlW2HuFt6mPo4OfDYodltN52cR6EFvyc7d0X3Sg==" />

  <fieldset id="recipe-meta">
    <ol>
      <li class="control-group">
        <label class="control-label" for="recipe_title">Recipe Name</label>
        <div class="controls"><input type="text" value="Test2" name="recipe[title]" id="recipe_title" /></div>
      </li>
      <li class="control-group">
        <label class="control-label" for="recipe_description">A brief description of this recipe</label>
        <div class="controls"><textarea rows="5" name="recipe[description]" id="recipe_description">
Test2</textarea></div>
      </li>
      <li class="control-group">
        <label class="control-label" for="recipe_instruction">Instructions for this recipe</label>
        <div class="controls"><textarea rows="10" name="recipe[instruction]" id="recipe_instruction">
Test2</textarea></div>
      </li>
    </ol>
  </fieldset>

  <fieldset id="recipe-ingredients">
    <ol>

        <li class="control-group nested-fields">
  <div class="controls">
    <label for="recipe_quantities_attributes_0_amount">Amount:</label>
    <input type="text" value="111" name="recipe[quantities_attributes][0][amount]" id="recipe_quantities_attributes_0_amount" />


    <input type="hidden" name="recipe[quantities_attributes][0][_destroy]" id="recipe_quantities_attributes_0__destroy" value="false" /><a class="remove_fields existing" href="#">remove</a>
  </div>
</li>
<input type="hidden" value="38" name="recipe[quantities_attributes][0][id]" id="recipe_quantities_attributes_0_id" />
        <li class="control-group nested-fields">
  <div class="controls">
    <label for="recipe_quantities_attributes_1_amount">Amount:</label>
    <input type="text" value="111" name="recipe[quantities_attributes][1][amount]" id="recipe_quantities_attributes_1_amount" />


    <input type="hidden" name="recipe[quantities_attributes][1][_destroy]" id="recipe_quantities_attributes_1__destroy" value="false" /><a class="remove_fields existing" href="#">remove</a>
  </div>
</li>
<input type="hidden" value="39" name="recipe[quantities_attributes][1][id]" id="recipe_quantities_attributes_1_id" />
        <li class="control-group nested-fields">
  <div class="controls">
    <label for="recipe_quantities_attributes_2_amount">Amount:</label>
    <input type="text" value="1111" name="recipe[quantities_attributes][2][amount]" id="recipe_quantities_attributes_2_amount" />


    <input type="hidden" name="recipe[quantities_attributes][2][_destroy]" id="recipe_quantities_attributes_2__destroy" value="false" /><a class="remove_fields existing" href="#">remove</a>
  </div>
</li>
<input type="hidden" value="40" name="recipe[quantities_attributes][2][id]" id="recipe_quantities_attributes_2_id" />
        <li class="control-group nested-fields">
  <div class="controls">
    <label for="recipe_quantities_attributes_3_amount">Amount:</label>
    <input type="text" value="2222" name="recipe[quantities_attributes][3][amount]" id="recipe_quantities_attributes_3_amount" />


    <input type="hidden" name="recipe[quantities_attributes][3][_destroy]" id="recipe_quantities_attributes_3__destroy" value="false" /><a class="remove_fields existing" href="#">remove</a>
  </div>
</li>
<input type="hidden" value="41" name="recipe[quantities_attributes][3][id]" id="recipe_quantities_attributes_3_id" />
        <li class="control-group nested-fields">
  <div class="controls">
    <label for="recipe_quantities_attributes_4_amount">Amount:</label>
    <input type="text" value="33" name="recipe[quantities_attributes][4][amount]" id="recipe_quantities_attributes_4_amount" />


    <input type="hidden" name="recipe[quantities_attributes][4][_destroy]" id="recipe_quantities_attributes_4__destroy" value="false" /><a class="remove_fields existing" href="#">remove</a>
  </div>
</li>
<input type="hidden" value="42" name="recipe[quantities_attributes][4][id]" id="recipe_quantities_attributes_4_id" />
        <li class="control-group nested-fields">
  <div class="controls">
    <label for="recipe_quantities_attributes_5_amount">Amount:</label>
    <input type="text" value="444" name="recipe[quantities_attributes][5][amount]" id="recipe_quantities_attributes_5_amount" />


    <input type="hidden" name="recipe[quantities_attributes][5][_destroy]" id="recipe_quantities_attributes_5__destroy" value="false" /><a class="remove_fields existing" href="#">remove</a>
  </div>
</li>
<input type="hidden" value="43" name="recipe[quantities_attributes][5][id]" id="recipe_quantities_attributes_5_id" />    </ol>
    <a data-association-insertion-node="#recipe-ingredients ol" data-association-insertion-method="append" class="add_fields" data-association="quantity" data-associations="quantities" data-association-insertion-template="&lt;li class=&quot;control-group nested-fields&quot;&gt;
  &lt;div class=&quot;controls&quot;&gt;
    &lt;label for=&quot;recipe_quantities_attributes_new_quantities_amount&quot;&gt;Amount:&lt;/label&gt;
    &lt;input type=&quot;text&quot; name=&quot;recipe[quantities_attributes][new_quantities][amount]&quot; id=&quot;recipe_quantities_attributes_new_quantities_amount&quot; /&gt;


      &lt;input type=&quot;text&quot; name=&quot;recipe[quantities_attributes][new_quantities][ingredient_attributes][name]&quot; id=&quot;recipe_quantities_attributes_new_quantities_ingredient_attributes_name&quot; /&gt;

    &lt;input type=&quot;hidden&quot; name=&quot;recipe[quantities_attributes][new_quantities][_destroy]&quot; id=&quot;recipe_quantities_attributes_new_quantities__destroy&quot; value=&quot;false&quot; /&gt;&lt;a class=&quot;remove_fields dynamic&quot; href=&quot;#&quot;&gt;remove&lt;/a&gt;
  &lt;/div&gt;
&lt;/li&gt;" href="#">add ingredient</a>
  </fieldset>
    <input type="submit" name="commit" value="Update Recipe" />
  </div>
</form>

<a href="/recipes/2">Show</a> |
<a href="/recipes">Back</a>


</body>
</html>

回答1:


Your recipe_params method needs to be changed - you actually have two levels of nesting in your form (Recipe -> Quantity -> Ingredient) so your parameter permitting needs to reflect this.

In your method, remove the ingredient_attributes and ingredients_attributes part - they don't match the format of your submitted params. Instead, you want something like the following:

:quantities_attributes => [:id, :ingredient, :ingredient_id, :recipe_id, :amount, 
  :_destroy, :ingredient_attributes => [:id, :_destroy, :ingredient_id, :name]]


来源:https://stackoverflow.com/questions/34457789/ruby-on-rails-4-missing-form-field-after-commit-error-is-unpermitted-paramet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!