In the last chapter, we saw how to create a new task and save it to the
database. Let's add a new feature to display the newly created task.
Features
These are the requirements of this feature:
-
A show button should be present for each task. User should be redirected to
task details page on clicking the show button.
-
Task details page should only contain the task title for now. Below is a
picture showing how UI would look like once implemented.
Do not get overwhelmed by the edit and delete buttons as well as the comment
section. We will cover those features later in this book.
Technical design
To implement this feature, we need to introduce the following changes:
On the backend
-
Add a show
route for tasks RESTful resources in the routes file.
-
We will add a show
action in the TasksController
. When the application
receives the request to show a task, that request will be processed by the
show action.
On the frontend
-
Add a GET API connector for fetching a task inside the tasks API collection.
-
Add a Show
component which will receive the task slug
using URL params.
Show
component will call the API to fetch a task and display the task
details.
-
In the Dashboard
component, add a new showTask
function which will
redirect the application to a new page based on the task slug using
react-router-dom
.
-
Pass down showTask
function as a prop to the Row
component through the
Table
component.
-
Add a new Route in the App
component for the task page. This route should
render the Show
component.
Implementing show action in TasksController
Open /app/controllers/tasks_controller.rb
and add the following lines of code:
In the show
action we are trying to find and respond with a task by filtering
using the slug
attribute.
Note that in the above action we have used the find_by!
method which will
raise an exception if no matching record is found in the database. We do not
need to worry about handling the exception anymore as we have already handled
that inside the ApplicationController
.
After the task is loaded successfully, the render_json
method responds with an
:ok
status and the task
json.
We have chosen the render_json
method over the render_notice
method here
because render_notice
method also sends back a success message along with a
json which gets displayed as a notification in the client-side. We do not want
to send a success message in this case.
Building Show Component
Let's first create our task's show component:
In Show.jsx
, paste the following content:
useParams
hook is provided by the react-router-dom
package and it returns an
object of URL parameters as key/value pairs. For example, for
/tasks/:task-slug
, useParams
will return the following object:
Let's now create an API route to handle our show request in
app/javascript/src/apis/tasks.js
.
Note: Until now we have been using highlighted lines of code to show what
needs to be added to the codebase/component.
However, from here onwards, since we will be making a lot of changes and
additions to each of the components, if we haven't highlighted any lines in code
block, then the best way to stay in sync is to copy the whole code snippet and
replace the corresponding component/file in your local project with that
content, unless specified otherwise.
App.jsx
will only require updates in most chapters, rather than full
replacement.
This will help you from not missing out on any of the changes that needs to be
reflected in your local project.
Now update tasks.js
with the following content:
Now we will create a showTask
handler function in the Dashboard
and pass it
down to the Table
component. Fully replace
app/javascript/src/components/Dashboard/index.jsx
with the following content:
We need to pass down showTask
function as props to Row
component and attach
it to an onClick
event which will be fired upon clicking the show button.
To do so, update app/javascript/src/components/Tasks/Table/index.jsx
with the
following lines of code:
Then, update the content of Row.jsx
with following lines:
Now we have completed adding the show action handler for a task and hooked it to
the onClick
event. The last step is to define a route inside of App.jsx
to
render our tasks show page.
But while importing the Show
component in App.jsx
we will be using the same
namespace as in Create
component which is components/Tasks
.
Here we can add an index.js
file to components/Tasks
to reduce the number of
import statements in App.jsx
and also to make things look cleaner.
These conventions are documented in
this chapter
in our React Best Practices Book.
Create a new file index.js
in app/javascript/src/components/Tasks
and add
the following lines:
Here, we have imported the Create
and Show
as CreateTask
and ShowTask
because outside the tasks
namespace or inside App.jsx
names like Create
and Show
can be very confusing and may also give errors as there can be
multiple Create and Show from different folders(namespaces). Thus it's better to
export them as CreateTask
and ShowTask
.
Now add the highlighted lines to App.jsx
:
Now, let's go to the dashboard URL and click
on the Show
button, we might see that an error has occurred:
We are getting an error because the Rails router can't find any route matching
the format /tasks/:slug
for a GET
request or more accurately since we
haven't defined show
action in task resources
.
Let's solve this by adding that action into /config/routes.rb
.
Note: It is possible that you're able to access the show page for an individual
task even before updating the routes.rb
file without encountering any routing
error.
But the issue that you might notice is that the title of the task will remain
empty as we are not able to fetch details from the backend due to absence of the
corresponding API route for returning the title details.
Adding the route in the following step will allow us to view the show page with
title of the task:
Now if we visit dashboard URL and then click
on Show
button corresponding to a task, we will be able to see the details of
that task.
Using Rails console to search tasks
Let's fire up the console once again using the rails console
command:
As shown above, we use the find_by
method and pass it with any slug
.
If an entry in the database exists with corresponding slug, then the record is
fetched otherwise exception is returned.
You can use the find_by!
method which will raise an
ActiveRecord::RecordNotFound
exception if no tasks with a matching slug is
found in the database.
We can also use other attributes to look for a specific task using the where
method.
Let's try with the title
attribute:
Now let's commit these changes: