Refactoring CanCan(Can) Abilities
- Use Arrays
- Prefer hashes to blocks
- If you use concerns, use concerns
cannotfor exceptions instead of blocks
#mergeto extract logic from your main ability
- Further Reading
If you have a somewhat complicated set of authorization-rules in your system, your CanCan(Can) Abilities can become quite unwieldy. Here are some tips to make them more manageable.
There is an antipattern when using
CanCan::Ability, that iterates over objects or verbs to define a bunch of rules that could be expressed a lot easier. Example:
This defining 3 rules, where only one is needed.
Prefer hashes to blocks
Block arguments to rules are slow and cannot be used in db-queries. If you can (and you won’t always be able to) you should instead use hash-arguments:
If you use concerns, use concerns
cannot for exceptions instead of blocks
If you have exceptions to a rule, or negative conditions, try to use
Again, this is slow and not SQL compatible. Instead use something like this:
Remember the rule-precedence of CanCan: Rules you define later will override the earlier ones.
#merge to extract logic from your main ability
If you tried all of the above but somehow still have a file that is way to long, you can try to split it into multiple small abilities (you could call them faculties).
This way you can keep the scope and responsibility of your ability small, and your faculties easily testable.
You can always have a look at the official best practices or if you are feeling adventurous you can
gem open cancancan and have a look into the source code yourself!