In the last chapter, we saw how to update a task. In this chapter we'll see how
to delete a task.
Features
These are the basic requirements of the feature:
-
A delete button should be present for all tasks.
-
Upon clicking the delete button, a DELETE
HTTP request should be sent to the
backend.
-
Once a response is received for the DELETE
request a notification should be
displayed with a success message or error message depending upon the response
status.
-
No notification should be displayed if a task is successfully deleted because
from a UI perspective the result of this action will be visible and showing a
notification on top of it will be an overkill in this case.
Technical design
To implement this feature, we need to introduce the following changes:
On the backend
-
Add a destroy
route for tasks RESTful resources in the routes file.
-
Add a destroy
action in the TasksController
. When application receives a
DELETE request to delete a task, it will be processed by the delete action.
-
Update the before_action
callback in the TasksController
to call the
load_task!
method before destroy
action is called.
On the frontend
-
Add a DELETE
request API connector for deleting a task.
-
Update the Dashboard
component and add a deleteTask
function which will
handle the logic to delete the task.
-
Pass deleteTask
function as a prop to the Row
component through Table
component.
-
Update the Row
component and add a delete button which will call the
deleteTask
function received through props.
-
Add a route in App
component for rendering the Edit
component from Tasks
folder.
Implementing destroy action in TasksController
Let's implement the destroy
action in our TasksController
.
Add the following lines of code into TasksController
:
Here, load_task!
methods runs before the destroy
action and will have
fetched the task
whose slug
matches our request parameter's slug
value.
We do not need to send a json along with the response when a task is deleted
successfully that is why we are responding with the render_json
method which
will send a response with an
ok status and an
empty json if nothing is passed as an argument.
Now, update the tasks resources in config/routes.rb
file:
Handling task deletion
When user clicks on the "Delete" button then we need to handle that click. Then
send a request to the server to delete the task. Let's handle it.
First, let's add an API for deleting a task. To do so, add the following lines
to app/javascript/src/apis/tasks.js
:
Open app/javascript/src/components/Dashboard/index.jsx
and fully replace the
content of the file with the code shown below.
Now, we need to pass down destroyTask
function as props to Row
component. To
do so, update app/javascript/src/components/Tasks/Table/index.jsx
with the
following lines of code:
Now, we need to make use of the destroyTask
function so that a click on the
Delete
button in the tasks table would delete the corresponding task.
To do so, go to app/javascript/src/components/Tasks/Table/Row.jsx
and add the
following lines:
Destroying all in batches
If we invoke destroy_all
method on a list of thousands of records then it can
cause db and memory issues.
The destroy_all
method loads the entire relation and then iteratively destroys
the records one by one which can blow the memory very easily. Moreover, if we
are destroying 5000 records using the destroy_all
method then it places the db
in a transaction lock. So this will prevents any other db calls from being
executed and will cause APIs to timeout during the time db is locked.
So while using destroy_all
method we should prefer using batches, like this:
This would ensure that the records are destroyed in a batched fashion so that
the memory and API calls don't take any hit.
Deleting a task
So let's go through the Destroy flow of our task.
When we click the delete
button, the onClick
function uses the
destroyTask()
for making the API call and handles the task deletion provided
the correct route and slug
of the task.
The control then goes to the router and router directs the control to destroy
action of the TasksController
.
Once it's done, we again fetch the list of tasks from the DB, because the
database should be the source of truth for the data we show in UI in all cases.