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:
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.
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.
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!
Go ahead and add a few more tasks.