Need help understanding turbo in rails 7

112 Views Asked by At

Everything all around is just acting weird. I can create todo objects but they are only displayed after I refresh, I have had this same issue on 2 separate occasions. I know that I am using the variables wrong but with so much going on it's hard for me to tell exactly what goes where. Rails is pretty picky but that seems to usually be my issue.

Even when I had them showing up after I created them the delete wouldn't take place until after I refreshed, and yes I tried method: :delete, and the data: {turbo_method: :delete}. If I could figure this out one time I would be thereafter but it's just not making sense.

Here is my code and I will even drop a link to my GitHub in case someone wants to run it and see exactly what I'm talking about. Im sure there are plenty of errors by now as much as I have been changing things.

https://github.com/gagegolden00/Turbo_Issues

CONTROLLER

class TodosController < ApplicationController
  before_action :set_todo, only: [:show, :edit, :update, :destroy]
  
  def index
    @todos = Todo.all
    @todo = Todo.new
  end
  
  def show
  end
  
  def new
    @todo = Todo.new
  end
  
  def create
    @todo = Todo.new(todo_params)
    if @todo.save
      render turbo_stream: turbo_stream.append('todos', partial: 'todo_partial', locals: { todo: @todo }),
             notice: 'Task was successfully created.'
    else
      render :new
    end
  end
  
  def update
    if @todo.update(todo_params)
      render turbo_stream: turbo_stream.replace('todos', partial: 'todo_partial', locals: { todo: @todo }),
             notice: 'Task was successfully updated.'
    else
      render :edit
    end
  end
  
  def edit
  end
  
  def destroy
    @todo.destroy
    render turbo_stream: turbo_stream.remove('todos', partial: 'todo_partial', locals: { todo: @todo }),
           notice: 'Task was successfully deleted.'
  end
  
  private
  
  def set_todo
    @todo = Todo.find(params[:id])
  end
  
  def todo_params
    params.require(:todo).permit(:name, :description, :status)
  end
end

FORM PARTIAL

<!-- _form_partial.html.erb -->

\<%= form_for(@todo, remote: true, html: { class: 'bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4' }) do |f| %\>

  
    <%= f.label :name, class: 'block text-gray-700 text-sm font-bold mb-2' %>
    <%= f.text_field :name, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %>
  
  
    <%= f.label :description, class: 'block text-gray-700 text-sm font-bold mb-2' %>
    <%= f.text_area :description, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %>
  
  
    <%= f.label :status, class: 'block text-gray-700 text-sm font-bold mb-2' %>
    <%= f.select :status, options_for_select(Todo.statuses.keys.to_a, @todo.status), {}, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %>
  
  
    <%= f.submit 'Submit', class: 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline' %>
  
<% end %>

TODO PARTIAL

<!-- _todo_partial.html.erb -->

\<%= turbo_frame_tag 'todos' do %\>

  
    <h3>
      <%= todo.name%>
    </h3>
    <p>Description: <%= todo.description %></p>
    Status: <%= todo.status %>
  
<% end %>

TODOS INDEX VIEW

  <h1>Index: List all todos</h1>

  <!-- List all the todo items -->

  
    <% @todos.each do |todo| %>
      <%= render partial: 'todo_partial', locals: { todo: todo } %>
    <% end %>
  

  <!-- Provide a form to create a new todo item -->

  
    <%= render partial: 'form_partial', locals: { todo: @todo } %>

TODOS SHOW VIEW

<h1>Show: Specific details about a certain todo</h1>
<!-- Display the details of the todo item -->
<p><strong>Title:</strong> <%= @todo.name %></p>
<p><strong>Description:</strong> <%= @todo.description %></p>
<p><strong>Status:</strong> <%= @todo.status %></p>

<!-- Provide a link to edit the todo item -->

\<%= link_to "Edit", edit_todo_path(@todo), remote: true %\>
\<%= button_to "Delete", todo_path(@todo), data: { turbo_method: :delete }, remote: true %\>
1

There are 1 best solutions below

0
On

When you manipulate the todo frame of your views, the frame should be the individual todo element and not the entire list of todos.

# create method
render turbo_stream: turbo_stream.append('todos', turbo_frame_tag(@todo, partial: 'todos/todo', locals: { todo: @todo }))

# update method
render turbo_stream: turbo_stream.replace(@todo, partial: 'todos/todo', locals: { todo: @todo })

# destroy method
render turbo_stream: turbo_stream.remove(@todo)

In the todo_partial.html.erb the frame id should be unique for each todo, instead of just 'todos'.

<!-- _todo_partial.html.erb -->

<%= turbo_frame_tag dom_id(todo) do %>
  <h3>
    <%= todo.name%>
  </h3>
  <p>Description: <%= todo.description %></p>
  Status: <%= todo.status %>
<% end %>

You can find more examples here: https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/frames_helper.rb

I also found this tutorial from hotrails.dev pretty straight-forward.

I am sorry if my code does not match your 100%. I hope this helps for the start.