2

I'm trying to create a list of items within a "Todo list", however, I'm not sure if I'm doing this correctly with nested attributes. I think using a nested attribute is the right attempt because there's going to be a large list of items, and it will be associated with the correct "Todo list" based on ids.

Example of what the tables might look like when records are populated

Todo table

id         list       
1          grocery shopping
2          health insurance

Item table

id         todo_id        name           
1          1              buy milk
2          1              buy cereal
3          2              Blue Shield
4          2              Healthnet
5          1              buy cherries

Although, with my attempt below, my application is not saving any of the data into the Item database.

Todo Controller

class TodoController < ApplicationController
  def new
    @todo = Todo.new
    @todo.items.build
  end
end

Todo Model

class Todo < ActiveRecord::Base
  belongs_to :user
  has_many :items
  accepts_nested_attributes_for :items
end

Item Model

class Item < ActiveRecord::Base
    belongs_to :todo
end

Todo View

<%= simple_form_for(@todo) do |f| %>
  <%= f.input :list %>

  <%= f.simple_fields_for :items do |g| %>
    <%= g.input :name %>
  <% end%>

  <%= f.button :submit %>
<% end %>

I was able to have the name field show up in my view, but when I save it, it doesn't save into the database, however, I'm able to save the list into the database, and then when I try to edit the record, the name field doesn't show up anymore to be able to edit.


EDIT: to show create method

This is my current Create Method in Todo Controller

def create
  @todo = Todo.new(todo_params)

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

Not sure if Edit needs to have something, but I only have this from generating a scaffold of Todo

def edit
end

EDIT 2 show todo_params

def todo_params
  params.require(:todo).permit(:user_id, :list)
end
13
  • Shouldn't that be 'fields_for :items'? Commented Jul 14, 2015 at 23:39
  • @AJFaraday oops, you're right. I don't know why I wrote that... it mustve been the television that I'm watching... Thanks! Commented Jul 15, 2015 at 0:02
  • Okay, the TodosController needs a create method. If it has one, it may help to include it in the question. Also, what does the log look like when you're submitting the form? Does it go to TodosController#create? Does the :todo hash inlude an arribute called "items"? Commented Jul 15, 2015 at 0:05
  • I've just seen your comment, did that solve the issue? Commented Jul 15, 2015 at 0:06
  • @AJFaraday no, that didn't solve the issue. Also, I updated my post to show create method. My log shows that it goes to #create, and it inserts into the todo table, but I don't see any insert into item table Commented Jul 15, 2015 at 0:31

2 Answers 2

4

You must add the nested params to your strong params

def todo_params
  params.require(:todo).permit(:user_id, :list, items_attributes: [:id, :text, ...])
end

Note about todo_id :

You don't need to add :todo_id in items_attributes list, because you already have the TODO as context.

@todo = Todo.new(todo_params)

In the above code, your todo_params will contain some item_attributes linked to @todo. ie, it's similar to doing

@todo.items.build

It will already create an item with a todo_id corresponding to @todo.id

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your help! How do I pass the parameters to ensure that it will save the id into todo_id? Is adding :todo_id enough? or am I supposed to do something like :todo_id => {params[:id]} or something? This might be wrong syntax...
Don't worry about this, you are adding nested attributes, so the items are already added under the context of a "Todo" (the todo_id is somewhat transferred to child items). The ID in items_attributes makes sure you can edit your items instead of creating new ones each tme ;-)
Okay cool thanks! Yeah I tried it, and it automatically saved it... Last question: If I didn't have a todo_id in my ITEM table, will this not work? I must have a relationship id to make this work right?
You are right. This what is expected when you write belongs_to :todo. With ActiveRecord, you need to manually synchronize your models with your database schema (migrations, etc. to make sure there's a todo_id column). If you try other DBs like MongoDB/Mongoid, your model becomes exactly your DB structure, without any need for migrations (and I find this wonderful tbh)
2

You need to add the items to the list of whitelisted attributes

def todo_params
 params.require(:todo).permit(
   :user_id, 
   :list,
   items_attributes: [ # you're missing this
     :id,
     :name
   ]
 )
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.