More Performance in Cancancan



If you use Ruby On Rails, you probably % 90 know Cancancan gem when you need some authorization and ability.
Generally, in the first times experiences everything might be easy. When you start a basic application everything very fast and basic in Rails application. When you added some modules and features can be a little hard to manage your application. After 1 year, if your company or your application still living, you start to think of Rails application performance. You start to fix N+1 problems. You start to improve Active Record Queries. I am seeing to hear your words, why this request takes 5 seconds. :) You start to use the caching mechanism. (For Rails caching https://guides.rubyonrails.org/caching_with_rails.html).

Run queries by controls and paths

And if you start to think, why there are a lot of DB Queries in logs.
If you use Cancancan gem, you need caching role queries and some (if) cases according to by request paths, controllers.
I’ll try to inform you about my live production application in the real world. I have some models, controllers like every Rails application. And I have almost 10 different roles and some abilities. What is easier to manage and control these roles and abilities, of course, this is Cancancan gem in Rails world.
First codings :


In these codes, you are seeing some role cases in Cancancan gem. There are no any if cases and when we call an API, the block will run all models. For example, you need some order count from active record query and you need just actually just Order model query in this case.
There is no check case according to the paths or controllers.
When you call :

This method will touch all models and getting a lot of Queries in your debug level logs :



In Postman, totally loading time :
Time: 1393ms — Size: 678 B
Right now, there is a performance problem. How to fix? Why Cancancan touches all models? I need just actually just Order model queries:



Solution

We can separate model by model by the what we need in API Query.
Firstly we need a controller name or path or full path in our application.
ApplicationController.rb class

We need pass this params to Ability.rb class initialize

and finally about our role blocks :

Then , calling API result in Postman :
And your debug logs :

Time:111ms — Size:678 B
In fact, the solution is very simple, but you have to look for it. I learned this by experimenting with the need.

Caching Everytime

Cancancan needs to check your roles in every active record request. These calls will get some performance problems. We saw these problems above pictures.
What is your base user models in your live application? I have just one user model that is User.rb. When we call some about Cancancan methods that are like has_role?() or has_any_role?() , will touch every time to DB. But when we touch just one time in DB, that is should be enough getting the right roles and abilities without second or third touches to DB.
We can benefit the Rails cache in this situation. We cached and we get every time caching about role specifications.

And you need just to add in your User.rb model :

You blocked many queries. Your database will thank you :)
See you next time.
I wish you happy coding.
:)

Comments

Popular posts from this blog

Design a notification system

NETFLIX HIGH-LEVEL SYSTEM DESIGN

URL Shortener System Design