How to Integrate Advanced Callbacks in Rails
In this lesson, we are going to learn to do conditional callbacks for our tasks.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this lesson, we are going to learn to do conditional callbacks for our task model. What this callback is going to do is it will look at the task every time it is saved, and if it is marked complete, the callback will increase the count of the parameter percent_complete of the project that the task belongs to.

To do this, go to the task.rb file and type the code

after_save :update_percent_complete if :mark_completed?

This callback after_save will be called when a task is created and it is marked as complete. It will also be called when a task is updated and marked as complete.

large

Next, we are going to create two methods called mark_completed? and update_percent_complete.

Now, what this code will do is it will run the method update_percent_complete if the mark_completed method returns a true value. In Ruby, a method will come back as true if the value is not nil and not false.

Inside the mark_completed method, type this code:

self.completed == true

What this means is if the completed parameter of that particular instance of Task is true, then the method will return a true value. On the other hand, if this parameter does not have the value true, then the method will return false and nothing else will happen.

Next, let's create our update_percent_complete method:

def update_percent_complete
  project = Project. find(self.project_id)
  count_of_completed_tasks = project.tasks.completed.count
  count_of_total_tasks = project.tasks.count
  project.update!(percent_complete: Counter.calculate_percent_complete(count_of_completed_tasks, count_of_total_tasks))
end

In this method, in the first line, we are going to find the project with the project_id of that particular instance of task. This project is stored in a local variable called project.

In the second line, we are going to create a variable count_of_completed_tasks, and in this variable, we are putting the count of tasks that are marked as complete in that project. Now, we want the code to know what is completed, and for this we create a scope to the model:

scope :completed, -> {where ('completed: true')}

This scope tells the second line of code that completed means any task with a parameter of completed is marked as true.

In the third line, we create another variable called count_of_total_tasks and here we store the count of all the tasks in the project.

In the fourth line, we want to update the percent_complete parameter of our project record. To calculate what the value of percent_complete we are going to use the Counter class that we created a few lessons back. If you remember, this class has a method called calculate_percent_complete that takes two parameters. So, we invoke this method here with count_of_completed_tasks and count_of_total_tasks as its parameters.

large

Now, we can test it on our console. Start the console with the command rails c

Next, let's store the last project in a variable with the command

p = Project.last

This means the p variable will now have the value of the last project that has a project_id of 21. Let's now check if this project has any tasks with the command p.tasks

This returns two tasks for us. If you want to see the percent_complete value, type:

p.percent_complete.to_s

In this command, we are converting the value of "percent_complete" to a string value because it can be quite long otherwise. This value is currently 0.0

Next, let's see the completed value of the last task with the command Task.last. If you see, this command brings up the last task whose completed value is nil. Next, we update the completed value of this task with the command:

Task.last.update!(completed:true)

Now that the completed value has been changed to true for the task's record in the project with an id of 21, we can check the if the percent_complete is updated with the command:

Project.last.percent_complete.to_s

This returns a value of 50.0, which means, our code worked perfectly!

You can see all these commands below.

large

Next, we can check if the update function works by changing the value of completed to false again with the command:

Task.last.update!(completed: false)

After this is executed, next check the value of percent_complete with the command:

Project.last.percent_complete.to_s

and this returns a value of 0.0 again, which is what we want.

large

We were able to do all of this because tasks and projects are connected to each other.