<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Diogo Oliveira</title>
    <description>The latest articles on DEV Community by Diogo Oliveira (@peeweee).</description>
    <link>https://dev.to/peeweee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3258346%2F674b5c09-4870-439e-8eb7-f94f6e3fb69b.png</url>
      <title>DEV Community: Diogo Oliveira</title>
      <link>https://dev.to/peeweee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/peeweee"/>
    <language>en</language>
    <item>
      <title>Creating a simple todo app with hotwire + sqlite3</title>
      <dc:creator>Diogo Oliveira</dc:creator>
      <pubDate>Fri, 27 Jun 2025 19:22:07 +0000</pubDate>
      <link>https://dev.to/peeweee/creating-a-simple-todo-app-with-hotwire-sqlite3-4fh1</link>
      <guid>https://dev.to/peeweee/creating-a-simple-todo-app-with-hotwire-sqlite3-4fh1</guid>
      <description>&lt;p&gt;tldr&lt;/p&gt;

&lt;p&gt;Simple todo app that shows how to use stimulus and turbo for the tasks creation.&lt;/p&gt;

&lt;p&gt;To begin with, I create a model task, with name and completed as columns and then I created the index, create and destroy actions for the tasks_controllers.&lt;/p&gt;

&lt;p&gt;With you want to see the code, access this link: &lt;a href="https://github.com/diogobest/todo-hotwire-example/blob/main/app/controllers/tasks_controller.rb" rel="noopener noreferrer"&gt;https://github.com/diogobest/todo-hotwire-example/blob/main/app/controllers/tasks_controller.rb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our model is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;broadcasts_to&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:tasks&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;broadcasts_to creates an pub/sub channel called tasks. Every change like create, update, destroy from this model, will be sent to this channel. Later we will connect to it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;del&gt;The code is very simple, I don’t want to lose focus or add unnecessary complexity, feel free to clone / fork the project and change as you want.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;The next step is to create our views in project/views/tasks/index.html.erb. This file is the core of the this sample app. Here we’ll have the features to complete our task, to delete or add them. The code is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= turbo_frame_tag :tasks do %&amp;gt;  ## 1
  &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s2"&gt;"form"&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;## 2&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= turbo_stream_from :tasks %&amp;gt; ## 3
&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="vi"&gt;@tasks&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;## 4&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the code at: &lt;a href="https://github.com/diogobest/todo-hotwire-example/tree/main/app/views" rel="noopener noreferrer"&gt;https://github.com/diogobest/todo-hotwire-example/tree/main/app/views&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The turbo_frame_tag creates an empty frame content, but fetches the &lt;code&gt;tasks&lt;/code&gt; stream of contents that we created in our models&lt;/li&gt;
&lt;li&gt;This create the form to add a new task, the code is simple:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form_with scope: :task, data: { turbo_frame: "_top" } do |form| %&amp;gt;
  &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form.text_field :name, required: true %&amp;gt;
  &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:completed&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= form.check_box :completed %&amp;gt;
  &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt; &lt;span class="s2"&gt;"Save"&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% end &lt;/span&gt;&lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Connect to the tasks channel, it is the channel we created at the Task model.&lt;/li&gt;
&lt;li&gt;Render each task individually.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= turbo_frame_tag dom_id(task) do %&amp;gt;
  &amp;lt;div data-controller=&lt;/span&gt;&lt;span class="s2"&gt;"tasks"&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;%= task.id %&amp;gt;"&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;%= task.completed %&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;
      &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"checkbox"&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= "checked" if task.completed %&amp;gt;
      data-action=&lt;/span&gt;&lt;span class="s2"&gt;"click-&amp;gt;tasks#toggle"&lt;/span&gt;
    &lt;span class="sr"&gt;/&amp;gt;
    &amp;lt;h3&amp;gt; &amp;lt;%= task.name %&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= link_to 'Deletar', task_path(task.id), data: { turbo_method: :delete } %&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only consideration I have to do is the dom_id(task) command, that is getting the id of the task and creating a string like: “task_01”.&lt;/p&gt;

&lt;p&gt;Execute the app and try to delete and create new tasks&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
