A task manager without any tasks is boring. So let’s add a form using which the users can add new tasks.

Start by creating a new task in the index action on our TasksController. Our form will use this as the default task.

class TasksController < ApplicationController
  def index
    @tasks = Task.all
    @task = Task.new
  end
end

Next, we will create the form partial by adding a _form.html.erb file in the app/views/tasks directory. This form has an input field and a button to submit the task.

<%= form_with(model: task, class: "mb-7") do |form| %>
  <div class="mb-5">
    <%= form.text_field :description, placeholder: "Add new task", class: "inline-block w-96 px-3 py-2 mt-2 shadow rounded-md border border-gray-200 outline-none" %>
    <%= form.submit "Save", class: "btn py-2 ml-2 bg-blue-600 text-white" %>
  </div>
<% end %>

Add the following code to the index.html.erb file to display this form partial on the home page.

<h1 class="font-bold text-2xl">Task Manager</h1>

<div class="mt-4">
  <%= render "form", task: @task %>
</div>

Notice that we are rendering the form as a partial, so we can reuse it later, possibly in a separate page that lets users add more details to a task.

Partials allow you to break the rendering process into more manageable chunks. With a partial, you can move the code for rendering a particular piece of a response to its own file.

Finally, add some style in the application.tailwind.css file, so our buttons look good. I’ve also removed the flex class on my main element in the application.html.erb file to keep things simple.

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
    .btn {
        @apply mt-3 rounded-lg py-1 px-5 inline-block font-medium cursor-pointer;
    }
}

Now reload the page. You should see the following form:

new_task_form.png

If you add some text and click “Save”, the page reloads. However, opening the Devtools shows an error in the networks tab because we are not handling form submissions on the back-end.

dev_tools.png

Let’s fix it by adding a create action on the TasksController.

class TasksController < ApplicationController
  def create
    @task = Task.new(task_params)

    respond_to do |format|
      if @task.save
        format.html { redirect_to tasks_url, notice: "Task was successfully created" }
      else
        format.html { render :new, status: :unprocessable_entity }
      end
    end
  end

  private

  def task_params
    params.require(:task).permit(:description)
  end
end

Strong Parameters in Rails

You might wonder why we are using task_params method instead of fetching them directly from params hash.

This technique called strong parameters, and it allows you to choose which attributes should be permitted for mass updating and thus prevent accidentally exposing that which shouldn’t be exposed.

The require method is used to mark parameters as required, and permit is used to set the parameter as permitted and limit which attributes should be allowed for mass updating. source

To learn more, check out the following post: Why You Need Strong Parameters in Rails

Finally, update the index.html.erb template to show the notice message at the top.

<% if notice.present? %>
  <p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice">
    <%= notice %>
  </p>
<% end %>

<h1 class="font-bold text-2xl">Task Manager</h1>

<div class="mt-4">
  <%= render "form", task: @task %>
</div>

Let’s add a new task and hit the Save button. You should see the success message, saying that the task was successfully saved in the database.

success.png

But, wait? Where is my task? It’s not showing up because we haven’t added any code on our view template to display the tasks. Let’s fix that by adding the following code (the last div below) in the index.html.erb file.

<% if notice.present? %>
  <p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice">
    <%= notice %>
  </p>
<% end %>

<h1 class="font-bold text-2xl">Task Manager</h1>

<div class="mt-4">
  <%= render "form", task: @task %>
</div>

<div id="tasks">
  <h1 class="font-bold text-lg mb-7">Tasks</h1>

  <div class="px-5">
    <%= render @tasks %>
  </div>
</div>

We are again using the task partial in the <%= render @tasks %> statement, which is a shortcut for looping over each task and rendering the _task partial for that task. Also, remember that we had set the @tasks variable in our index action on the TasksController class.

So let’s create the _task partial by creating a _task.html.erb file in the app/views/tasks directory.

<div class="block mb-2">
  <%= task.description %>
</div>

If you reload the page, you will see our first task. Hey, we did it!

displaying_tasks.png

Go ahead and add a few more tasks.

more_tasks.png