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.