Database are great on optimizing queries, but sometimes cancancan builds joins
that might lead to slow performance.
This is why your rules are optimized automatically at runtime.
There are a set of "rules" to optimize your rules definition and they are implemented in the RulesCompressor
class.
You can always disable the rules compressor by setting CanCan.rules_compressor_enabled = false
in your initializer.
You can also enable/disable it on a specific check by using: with_rules_compressor_enabled(false) { ... }
Here you can see how this works:
A rule without conditions is defined as catch_all
.
can :read, Book, author_id: user.id
cannot :read, Book, private: true
can :read, Book
can :read, Book, id: 1
cannot :read, Book, private: true
becomes
can :read, Book
cannot :read, Book, private: true
cannot :read, Book
can :read, Book, author_id: user.id
becomes
can :read, Book, author_id: user.id
cannot :read, Book, private: true
becomes
# nothing
These optimizations allow you to follow the strategy of "Give Permissions, don't take them" and automatically ignore previous rules when they are not needed.