Reputation: 13
I have two model called TodoList
and TodoItem
. In the TodoItem index page, i'm showing new form and list of todo items. Everything works perfect But it generate an empty record while in browser.
class TodoItem < ApplicationRecord
belongs_to :todo_list
end
class TodoList < ApplicationRecord
has_many :todo_items, dependent: :destroy
end
controllers have:
class TodoItemsController < ApplicationController
def index
@todo_list = TodoList.find(params[:todo_list_id])
@todo_items = @todo_list.todo_items
@new_todo = @todo_list.todo_items.new
end
def create
@todo_list = TodoList.find(params[:todo_list_id])
@todo_item = @todo_list.todo_items.new(params.require(:todo_item).permit(:description, :complete_at))
if @todo_item.save
redirect_to todo_list_todo_items_path(@todo_list)
end
end
end
index.html.erb
<div>
<div>
<% form_with(model: [@todo_list, @todo_item], local: true) do |f| %>
<% f.text_field :description %>
<% f.submit %>
<% end %>
</div>
<ul>
<% @todo_items.each do |todo_item| %>
<li><%= todo_item.description %></li>
<% end %>
</ul>
</div>
Upvotes: 1
Views: 73
Reputation: 3290
It seems @new_todo
has been added to @todo_items
somehow in index
action:
def index
@todo_items = @todo_list.todo_items
@new_todo = @todo_list.todo_items.new
# The above line has a side effect: @todo_items = @todo_items + [@new_todo]
end
I'm not sure it's a bug or feature from Rails (I use Rails 6.1.1).
For a quick fix, you can change @todo_list.todo_items.new
to TodoItem.new
.
Upvotes: 0
Reputation: 102443
class TodoItemsController < ApplicationController
# use callbacks instead of repeating yourself
before_action :set_todolist, only: [:new, :create, :index]
def index
@todo_items = @todo_list.todo_items
@todo_item = TodoItem.new
end
def create
@todo_item = @todo_list.todo_items.new(todo_list_params)
if @todo_item.save
redirect_to [@todo_list, :todo_items]
else
render :new
end
end
private
def set_todolist
@todo_list = TodoList.find(params[:todo_list_id])
end
# use a private method for your params whitelist for readibility
# it also lets you reuse it for the update action
def todo_list_params
params.require(:todo_item)
.permit(:description, :complete_at)
end
end
You where setting a different instance variable (@new_todo
) in you index action. The polymorphic route helpers that look up the route helpers from [@todo_list, @todo_item]
call compact on the array. So if @todo_item
is nil its going to call todo_lists_path
instead - ooops!
You alway also need to consider how you are going to respond to invalid data. Usually in Rails this means rendering the new view. If you are rendering the form in another view such as the index view it can get kind of tricky to re-render the same view as you have to set up all the same data as that action which leads to duplication.
Upvotes: 1