Как передать в rails на страницу index.html.erb вложенные сущности?
Всем привет. Уже пару недель не получается сделать одну штуку, прошу помощи. Делаю приложение на rails с Туду-листами. Туду-листов можно создавать сколько-угодно, и в каждом Туду-листе можно создавать свои задачи.
Файл роутов выглядит так:
Rails.application.routes.draw do
devise_for :users
get 'users/new'
resources :todo_lists do
resources :todo_items do
member do
patch :complete
end
end
end
root "todo_lists#index"
end
Но есть проблема: я хочу вывести на страницу index не только TodoLists, но и TodoItems для каждого листа. Как мне передать на todo_lists#index и todo_list, и его айтемы?
Контроллер TodoLists:
class TodoListsController < ApplicationController
def index
if user_signed_in?
@todo_lists = TodoList.where(:user_id => current_user.id)
end
end
end
Модель TodoList:
class TodoList < ApplicationRecord
belongs_to :user
has_many :todo_items
end
Модель TodoItem
class TodoItem < ApplicationRecord
belongs_to :todo_list
end
Далее вью. Для удобства разбила index.html.erb и _todo_list.html.erb, лежат в одной папке:
index.html.erb
<% if user_signed_in? %>
<% @todo_lists.each do |todo_list| %>
<%= render "todo_list", todo_list: todo_list %>
<% end %>
<div class="main-button-wrapper">
<button id="main-button">
<%= link_to "Add TODO List", new_todo_list_path %>
</button>
</div>
<% else %>
<%= render 'layouts/static_home_page' %>
<% end %>
_todo_list.html.erb
<div class="index_row clearfix" id="list-id-<%=todo_list.id%>">
<h2 class="work-task--top-panel_title"><%= link_to todo_list.title, todo_list %></h2>
<div class="top-panel_buttons">
<%= link_to image_tag("#"), edit_todo_list_path(todo_list) %>
<%= link_to image_tag("#"), todo_list_path(todo_list), method: :delete, data:{ confirm: "Are you sure?" } %>
</div>
</div>
<div class="work-task--input-field" id="list">
<%= form_for([todo_list, todo_list.todo_items.build]) do |f| %>
<%= f.text_field :content, placeholder: "New TODO" %>
<%= f.submit %>
<% end %>
</div>
<div class="work-task--list">
<div class="work-task--list__wrapper first-column">
<%= render todo_list.todo_items, todo_list: @todo_list %>
</div>
</div>
<%= render todo_list.todo_items, todo_list: @todo_list <--- одна из неудачных попыток передать в Todo Items todo_list_id.
-Этот лежит в отдельной папке todo_items-
_todo_item.html.erb
<div class="row clearfix flex-class">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(@todo_list, todo_item.id), remote: true, method: :patch do %>
<input type="checkbox" name="checkbox" checked>
<% end %>
</div>
<div class="todo_item" style="opacity: 0.4;"><strike><%= todo_item.content %></strike></div>
<div class="move show-button">
<%= link_to image_tag("#")%>
</div>
<div class="edit show-button">
<%= link_to image_tag("#"), edit_todo_list_path(@todo_list) %>
</div>
<div class="trash show-button">
<%= link_to image_tag("#"), todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data:{ confirm: "Are you sure?", class: "deleteAction" } %>
</div>
<% else %>
<div class="complete">
<%= link_to "Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), remote: true, method: :patch %>
</div>
<div class="todo_item">
<%= todo_item.content %>
</div>
<div class="move show-button">
<%= link_to image_tag("#") %>
</div>
<div class="edit show-button">
<%= link_to image_tag("#"), edit_todo_list_path(@todo_list) %>
</div>
<div class="trash show-button">
<%= link_to image_tag("#"), todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data:{ confirm: "Are you sure?", class: "deleteAction" } %>
</div>
<% end %>
</div>
Ответы (1 шт):
Всё просто, _todo_item.html.erb - это партиал, вам надо отрендерить его для каждого айтема. У вас это не получается из-за того, что в партиале вы пытаетесь использовать instance variable @todo_list.
Это плохая практика, партиалы могут рендериться в очень разных частях проекта, бывает очень сложно отследить, откуда именно прилетает эта переменная. Поэтому в партиалах принято использовать только локальные переменные и передавать их в партиал при рендеринге.
Во-первых, замените в _todo_item.html.erb @todo_list на todo_list
Во-вторых, замените
<%= render todo_list.todo_items, todo_list: @todo_list %>
на
<%= render partial: 'todo_items/todo_item', collection: todo_list.todo_items,
as: :todo_item, locals: { todo_list: todo_list } %>
В-третьих, сделайте то же самое для всех остальных партиалов в проекте
Более подробно про работу с партиалами можно почитать в официальных доках