Features
Let us introduce a new feature to let users star and unstar tasks. Starred tasks
are of higher importance than unstarred ones. This helps users organize their
important tasks easily.
These are the requirements of the feature.
-
Starred tasks should always be displayed at the top. They should be sorted
based on the time of starring. That is, the last starred task should be shown
at the very top.
-
We need to show a star icon on every task row in the list. Clicking on this
icon should toggle the starred/unstarred status of the task.
-
No success notification should be displayed when a task's status is updated.
-
Both the assignee and creator should be able to star/unstar a task.
-
Both starred and unstarred tasks will have star-shaped icons attached to them.
Starred tasks should have a bright yellow filling and the unstarred ones will
be left transparent with white borders. This will let users identify starred
tasks quickly.
Technical design
To implement this feature, we need to introduce the following changes:
On the backend
-
Add a new column in tasks
table to store the starred status of the task.
-
Add a new enum attribute called status
in the Task
model with two possible
values: starred
and unstarred
.
-
Permit the status
parameter when retrieving the Action Controller parameters
for task
, such that we can persist latest status to database.
-
For pending as well as completed tasks, we will load the starred and unstarred
tasks separately and sort them, then merge them using the
+ operator of
arrays.
-
For the purpose of sorting tasks, we will use the order
method of
ActiveRecord
class which accepts one or more than one column names of a
table along with the order direction. It returns a collection of records which
are sorted on the basis of the columns passed as argument, in the direction
specified.
-
For ensuring authorization, we do not need to do anything. In the code we
wrote earlier, no params
except title
and assigned_user_id
are
restricted. So status
will be accessible to both creator and assignee.
On the frontend
-
Add a new column in the list view displaying the starred status icon. CSS
classes are applied to this icon based on the value of the task's status
.
-
Add a new function in the Dashboard
component to toggle starred state of a
task. This function will be using the update API like the
handleProgressToggle
function.
-
Pass this function as props to the Row
component and use it as the click
handler of the star icon.
We are now ready to start coding. Let us dive in.
Storing starred status in DB
Let's create a migration to add a column called status
to the tasks
table:
Open db/migrate/add_status_to_tasks.rb
file and add following lines:
Now let's run the migration:
Now let's define an enum in models/tasks.rb
. Add the following line:
Let's go ahead and permit a parameter called status
. Let's update the
task_params
method as shown below:
Like we did for progress
in the
previous chapter,
we also need to add a value for status
to task
factory. Add the following
line to test/factories/task.rb
:
Update index action to send starred status
Now let us update our index action to retrieve the sorted list of tasks using
the order
method we have discussed earlier.
Now take a moment, and check if there's something that we can improve in the
above mentioned index
action.
Our index
action is starting to get longer. Also, we are now repeating a
similar block of code for both pending and completed tasks.
The Rails ideology is to keep the controllers as skinny as possible. That is why
we often delegate the logic into concerns
, helpers
etc.
So let us move the repeating piece of code to the Task
model:
Inside the of_status
method, we are conditionally querying the tasks based on
their progress
. We can call this method in task controller's index action and
pass the progress as an argument.
The of_status
method returns the tasks in such a way that the starred
ones
precede the unstarred
ones. Also, these tasks are sorted in decreasing order
of their updated_at
timestamp i.e the last updated task is returned first.
This is achieved with the help of the built-in in_order_of
method from Rails.
This method allows you to specify an explicit order while fetching an active
record collection. Since the result returned by the method is an
ActiveRecord::Relation
object, we can chain other scopes or query methods with
it. You can learn more about the in_order_of
method in this
PR.
Let's update the index
action in tasks_controller
to make use of the class
method that we wrote. Replace the index
method with the following content:
See, our index
method is much simpler to read now.
Update the highlighted lines in app/views/tasks/index.json.jbuilder
:
Adding a toggle to star/unstar tasks
Now, let's add the method starTask
. It would use the update API to toggle the
status of the task.
Replace app/javascript/src/components/Dashboard/index.jsx
with the following
code:
We do not want to show a success notification when a task is starred/unstarred
hence we have added a quiet
query param in the API call for updating the task
status like we did for task progress update API in the previous chapter.
We don't need to make any changes to the update
action in the backend or to
the update tasks API connector.
In app/javascript/src/components/Tasks/Table/index.jsx
, forward the starTask
function to Row
component.
Replace content of app/javascript/src/components/Tasks/Table/index.jsx
with
the following code:
Note that, we will only be allowing the user to star/unstar tasks which are not
yet completed. Thus, replace Row
with the following code:
Start the Rails server and verify everything is working fine. Now, a user should
be able to star/unstar tasks by clicking on the icon from their dashboard.
Now let's commit these changes: