bpromas
bpromas

Reputation: 694

Creating multiple children at the same time as I create the parent

I'm working on a simple rails task list app for learning purposes, and one of the things I would like to have on the app is to be able to create a new list at the same time as I can add in the tasks within that list. I have finalized the basic CRUD actions for creating lists, and now I want to add the capability for creating tasks at the same time as the creation of lists.

I have done some of the initial associations like so:

My List model:

class List < ApplicationRecord
  has_many :tasks
  accepts_nested_attributes_for :tasks
end

My Task model:

class Task < ApplicationRecord
  belongs_to :list
end

Also I've changed my list_params to return the tasks aswell:

def list_params
  params.require(:list).permit(:title, :public, task_attributes: [:text])
end

Now my problem is with how to write the form for my list with the possibility to add a dynamic number of tasks within it, then send those tasks over to my create action in order to save it.

My new action is as simple as it gets:

def new
  @list = List.new
end

My current form is like so:

<%= form_with scope: :list, url: lists_path, local: true do |form| %>
  <p>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </p>
  <p>
    <%= form.label :public %><br>
    <%= form.check_box :public %>
  </p>
  <h2>Tasks</h2>
  <%= form.fields_for :tasks do |task_form| %>
    <p>
    <%= task_form.label :text %><br>
    <%= task_form.text_field :text %><br>
    </p>
  <% end %>
  <p>
    <%= form.submit %>
  </p>
<% end %>

I intend to use this for testing purposes, to first create a list with one task, then one with two tasks, and then finally create some code to be able to add new fields via javascript so I can create an indefinite number of tasks. The problem I am arriving at however, is that when I submit this form, and call params at my create action, I can see it contains my task:

params

{\"utf8\"=>\"✓\", \"authenticity_token\"=>\"...\", \"list\"=>{\"title\"=>\"list\", \"public\"=>\"0\", \"tasks\"=>{\"text\"=>\"task\"}}, \"commit\"=>\"Save List\", \"controller\"=>\"lists\", \"action\"=>\"create\"}"

But when I try to see what's contained within my list_params what I get omits the tasks:

list_params

{\"title\"=>\"list\", \"public\"=>\"0\"}"

And beyond that, if I add two text fields in my tasks form, say filled with "task1" and "task2", what I get in the params is only "task2", seemingly overwriting the previous task.

So my problems are

1) Am I doing my form correctly? How should I change it so it allows for multiple tasks?

2) Why doesn't my list_params return any data from the task?

and I guess as a bonus, is there anything else that I am missing to be able to save a list at the same time as it's tasks?

EDIT: Here's the github link for my project if anyone wants to try it: https://github.com/bpromas/task-list

Upvotes: 0

Views: 111

Answers (2)

Kandy
Kandy

Reputation: 292

I created a new rails app and tried to follow the code you provided.

rails new a
rails generate scaffold List title public:boolean
rails generate scaffold Task text list:references
rails db:migrate

Then I edited the models like yours

app/models/list.rb

class List < ApplicationRecord
  has_many :tasks
  accepts_nested_attributes_for :tasks
end

app/models/task.rb

class Task < ApplicationRecord
  belongs_to :list
end

Now I looked your code and I did not understand how you initialized the tasks to be displayed in form.fields_for. I am going to print two possibilities that I am aware.

First possibility is creating a new instance of Task in _form.html.erb

<%= form.fields_for :tasks, Task.new do |task_form| %>
   <p>
      <%= task_form.label :text %><br>
      <%= task_form.text_field :text %>
   </p>
<% end %>

Second possibility is building new instances of Task in lists_controller.rb

def new
  @list = List.new
  @list.tasks.build
end

My list_params method is the same

def list_params
  params.require(:list).permit(:title, :public, tasks_attributes: [:text])
end

For me with all the steps above the app is working properly saving the tasks for the respective list. Check out if the console is displaying a red message like that "Unpermitted parameter: :tasks_attributes", if so there is some missing step you need to look at.

The time you make this work then to change the code to display more task fields is easy, just pass an array of new Task in _form.html.erb or create more builds in lists_controller.rb

First alternative

<%= form.fields_for :tasks, [Task.new, Task.new] do |task_form| %>
   <p>
      <%= task_form.label :text %><br>
      <%= task_form.text_field :text %>
   </p>
<% end %>

Second alternative

def new
  @list = List.new
  2.times { @list.tasks.build }
end

Good luck !!

Upvotes: 0

Max Vinicius
Max Vinicius

Reputation: 647

Maybe this can help you.

Take a look at this gem: https://github.com/nathanvda/cocoon

Upvotes: 1

Related Questions