Now that we have everything in the right place we are all set to introduce a new
feature to update a task.
Features
These are the requirements of this feature:
-
An edit button should be present for each task. User should be redirected to
edit task page on clicking the edit button.
-
Edit task page should contain a form with pre filled values of the task.
-
Upon clicking the submit button in the edit form, a PATCH request should be
sent with the updated task values.
-
A notification should be displayed stating whether the update operation was
successfully reflected in our database or not.
-
User should be redirected to the Dashboard once a task is successfully
updated.
Technical design
To implement this feature, we need to introduce the following changes:
On the backend
-
Add an update
route for tasks RESTful resources in the routes file.
-
Add an update
action in the TasksController
. When application receives a
PATCH request to update a task, it will be processed by the update action.
-
Add a before_action
callback to invoke load_task!
method which will load
the requested task before both show
and update
actions are called.
On the frontend
-
Add a PATCH request API connector for updating a task.
-
Create an Edit
component which will receive the task slug
through URL
params. It will also contain the reusable Form
component which will provide
an edit form.
-
Update the Show
component and add an updateTask
function which will handle
the logic to redirect the application to edit page.
-
Edit
component will call the API to fetch a task and pass fetched data to
the Form
to pre-populate the fields.
-
Add a route in App
component for rendering the Edit
component.
Implementing update task
We will start by adding the update
action in TasksController
. Let's open
/app/controllers/tasks_controller.rb
and change the code as shown below:
We have used the update!
method to save the updated values.
If the update is successful, we will return status
ok with a
notice. And on failure, the exception raised will be handled inside the
ApplicationController
.
In our update
action we are using the same line of code which we had written
in our show
action. The following is that line of code:
Finding tasks separately in every action will lead to repetition of code.
We should follow the DRY principle which we had learnt in the
Core Principles chapter.
Instead of finding task separately in every action, we can create a load_task!
method which we can run before certain actions using the before_action
filter.
By default before_action
filter will call the specified method before any or
specified actions are executed.
If we don't want to run the method before all the actions, then we can pass in a
hash as an argument, like this:
So it'll be applied only before those specified actions.
We can also pass in the hash with the except
key with an array of actions to
exclude. It means that before all other actions, except the excluded ones, our
before_action
filter method will get run.
Here the advantage is that we don't need to mention all actions manually. The
load_task!
method will run before all actions inside the TasksController
except the create
action.
Let's modify our TasksController
and use the before_action
filter.
Add the following changes to TasksController
:
Here, the load_task!
method will fetch the task using find_by!
method and
store it in @task
variable, before running the show
and update
actions.
find_by!
will raise an exception if no task is found with a matching slug.
Note that, we have used a bang operator with the load_task!
method name
because the method will return an exception n case a task is not found. It is a
Ruby convention for method names to end with a bang operator if they raise an
exception.
Now, update the tasks resources in config/routes.rb
file, like this:
Note that, we will be using the except
keyword over only
, since we only need
to exclude three actions and include the rest.
Let's now create a new component for updating task details. To do so, like
before, we will abstract the API
logic and form
logic to different
components.
First, let's add an API
route to edit tasks inside
app/javascript/src/apis/tasks.js
.
To do so, add the following lines to tasks.js
:
Now, let's create our React components to update task details. To do so, first
run the following command:
Inside Edit.jsx
, add the following content:
Add the new export in Tasks/index.js
file, like this:
Form
is the reusable UI that we had created while working on the chapter to
create a task.
Here, fetchTaskDetails
function is used to pre-populate the input
field with
the existing title of the task.
Now, we need to create a route inside of our App.jsx
.
To do so, open App.jsx
and add the following lines:
Now, add the updateTask
function to the Show
component.
To do so, fully replace app/javascript/src/components/Tasks/Show.jsx
with the
following lines of code:
Now, on the show task page, clicking on edit icon would render the Edit
component from Tasks
folder, where task details can be edited.
Moving response messages to i18n en.locales
Let's move the response messages to en.yml:
Let's update the update
action of TasksController
with the translation, like
so: