user2670683
user2670683

Reputation: 243

Rails 4.0 & Cocoon: nested fields under fields_for don't appear in Edit

Hoping someone can suggest a fix here. I am fairly new to Rails, and exploring the changes in Rails 4.0. I built this simple recipe book app in Rails 4.0. I have a main model for recipes (name, cook_time, oven_temp, instructions, etc.). Because some recipes may have 5 ingredients and others may have 20, I wanted to break ingredients out in a separate model with a has_many association. So Recipes has_many Ingredients and accepts_nested_attributes_for :ingredients. Here are the models:

recipe.rb

class Recipe < ActiveRecord::Base
  belongs_to :user
  belongs_to :category
  has_many :ingredients, :dependent => :destroy

  validates :name, presence: true, length: { maximum: 50 }

  accepts_nested_attributes_for :ingredients, 
                :reject_if => lambda { |a| a[:name].blank? },
                            :allow_destroy => true
end

ingredient.rb

class Ingredient < ActiveRecord::Base
  belongs_to :recipe
end

Reminder: Rails 4.0 no longer uses attr_accessible, but moves assignment into the controller with strong params.

recipes_controller.rb

class RecipesController < ApplicationController
  before_action :find_recipe, only: [:show, :edit, :update, :destroy]
  before_action :set_current_user, except: [:index, :show]
  respond_to :html, :js

  ...

  def edit
  end

  def update
    if @recipe.update_attributes(recipe_params)
      redirect_to @recipe
    else
      render :edit
    end
  end

...

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

private

  def recipe_params
    params.require(:recipe).permit( :id, :name, :category_id, :cook_time, :oven_temp, :calories, :instructions, :notes, :email, ingredients_attributes: [:id, :name])
  end

end

I'm using the excellent Cocoon gem from nathanvda to manage nested form fields dynamically, and it works great in 'recipes#new', and saves the information correctly. However, the ingredients fields do not appear in the 'recipes#edit' view! Here is the code for my 'form' and ingredients_fields partials.

_form.html.erb (abbreviated)

<%= form_for @recipe, html: { class: 'form-horizontal' } do |f| %>

  <fieldset>
  <legend>Main Information</legend>

    <div class="field form-group">
      <%= f.label :name, "Recipe name", class: "col-lg-2 control-label" %>
      <div class="col-lg-5">
        <%= f.text_field :name, class: "form-control" %>
      </div>
    </div>

    <div class="field form-group">
      <%= f.label :cook_time, class: "col-lg-2 control-label" %>
      <div class="col-lg-5">
        <%= f.text_field :cook_time, class: "form-control" %>
      </div>
    </div>
...
  </fieldset>

  <legend>Ingredients</legend>
  <p>Number of ingredients: <%= f.object.ingredients.count unless f.object.ingredients.nil? %></p>
  <fieldset id="ingredients">
    <% f.fields_for :ingredients do |builder| %>
      <%= render 'ingredient_fields', :f => builder %>
    <% end %>
    <p class="links">
      <%= link_to_add_association 'add ingredient', f, :ingredients, { class:"btn btn-primary" } %>
    </p>
  </fieldset>

  <fieldset>
  <legend>How to make it</legend>
  <div class="field form-group">
    <%= f.label :instructions, class: "col-lg-2 control-label" %>
      <div class="col-lg-5">
        <%= f.text_area :instructions, class: "form-control", rows: "7" %>
      </div>
    </div>
 ...
    </div>
  </fieldset>
<% end %>

_ingredients_fields.html.erb

<div class="nested-fields">
  <div class="form-group">
    <%= f.label :name, "Ingredient", class: "col-lg-2 control-label" %>
    <div class="col-lg-5">
      <%= f.text_field :name, class: "form-control" %>
    </div>
    <%= link_to_remove_association "remove", f %>
  </div>
</div>

As I said, pretty simple, removed all error checking and messaging, just the basics. Any ideas about what I am missing? I know there are ingredients in the recipe as I load edit from a show view. Thanks in advance for any advice!

Kevin

Upvotes: 3

Views: 3605

Answers (2)

Hemant Darpal
Hemant Darpal

Reputation: 21

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

Upvotes: 0

user2670683
user2670683

Reputation: 243

Ack. it was as simple as an '=' sign - must have looked at the <% f.fields_for... %> a thousand times and just didn't notice I'd missed adding the <%=.

Upvotes: 6

Related Questions