https://github.com/elado/kaching
Makes your DB suffer less from COUNT(*) queries and check-for-existence queries of associations (has_many and has_many :through), by keeping and maintaining counts and lists on Redis, for faster access.
https://github.com/elado/kaching
Last synced: about 1 month ago
JSON representation
Makes your DB suffer less from COUNT(*) queries and check-for-existence queries of associations (has_many and has_many :through), by keeping and maintaining counts and lists on Redis, for faster access.
- Host: GitHub
- URL: https://github.com/elado/kaching
- Owner: elado
- Created: 2012-01-25T19:23:18.000Z (over 13 years ago)
- Default Branch: master
- Last Pushed: 2012-12-19T09:21:41.000Z (over 12 years ago)
- Last Synced: 2025-03-28T07:11:32.833Z (about 2 months ago)
- Language: Ruby
- Homepage:
- Size: 175 KB
- Stars: 7
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# kaching
[](http://travis-ci.org/elado/kaching)
Makes your DB suffer less from `COUNT(*)` queries and check-for-existence queries of associations (has_many and has_many :through), by keeping and maintaining counts and lists on Redis, for faster access.
## Quick Intro & Examples
**Q: How does it help me?**
A: The short answer -- Less DB hits. More, faster Redis hits.
### Counters
```ruby
# hits DB
author.articles.count# first time hits DB and caches into Redis
author.articles_count# triggers an after_commit that increases the counter on Redis, doesn't run a count query on the DB
author.articles.create!(title: "Hello")# no DB hit. just reads from Redis
author.articles_count
```### Lists
```ruby
user.add_like!(memento) # writes to DB, updates Redis
user.likes_count # no DB hit
user.has_like?(memento) # no DB hit # => true
user.has_like?(inception) # no DB hit # => false
user.add_like!(inception) # writes to DB, updates Redis
user.has_like?(inception) # no DB hit # => true
user.likes_count # no DB hit # => 2
user.remove_like(inception) # deletes from DB, updates Redis
user.has_like?(inception) # no DB hit # => false
user.likes_count # no DB hit # => 1
```## Installation
```ruby
gem 'kaching'
```Requires Ruby 1.9.2+.
## Storage options
### Redis
```ruby
# config/initializers/redis.rb
$redis = Redis.newKaching::StorageProviders.Redis = $redis
```## cache_counter
Cache counts of associations.
Adds a count method to a class, and adds an after_commit callback to the countable class.
### Usage
```ruby
# article.rb
class Article < ActiveRecord::Base
belongs_to :user
end# user.rb
class User < ActiveRecord::Base
has_many :articlescache_counter :articles
end# code
user = User.create!user.articles_count # => 0
user.articles.create!(title: "Hello")
user.articles_count # => 1
````cache_counter` adds an after_commit to increase/decrease the counter directly on the data store.
#### More Options
Specify a `class_name` and provide a block to return a count for custom operations:
```ruby
class User < ActiveRecord::Base
cache_counter :following_users, class_name: 'Follow' do |user|
Follow.where(user_id: user.id, item_type: 'User').count
endcache_counter :follower_users, class_name: 'Follow', foreign_key: 'item_id' do |user|
Follow.where(item_id: user.id, item_type: 'User').count
end
end
```## cache_list
Caches presence of items in a list that is belong to antoer item. Automatically adds `cache_counter` on that association.
Example: User can Like stuff. In order to check if a user likes an item, you can run a query like
```ruby
Like.where(user_id: user.id, item_id: item.id, item_type: item.class.name).exists?
```But with many items and checks, this process might take some precious time.
In order to solve that, `kaching` fetches once all liked items and stores them in cache.
`cache_list :likes` generates these methods:
```ruby
add_like!(item)
remove_like!(item)
has_like?(item)
likes_count
reset_list_cache_likes!
```and from now on you can ask if `user.has_like?(item)`
```ruby
# like.rb
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :user, polymorphic: true
end# movie.rb
class Movie < ActiveRecord::Base
end# user.rb
class User < ActiveRecord::Base
has_many :likescache_list :likes
end# code
user = User.create!memento = Movie.create!(name: "memento")
inception = Movie.create!(name: "inception")user.add_like!(memento) # add_like! is an auto generated method!
user.likes_count # => 1
user.has_like?(memento) # => true
user.has_like?(inception) # => falseuser.add_like!(inception)
user.has_like?(inception) # => trueuser.likes_count # => 2
user.remove_like(inception)
user.has_like?(inception) # => falseuser.likes_count # => 1
```The first time `has_like?` is called, it collects all IDs of likes items and stores them in cache.
The second time just asks the cache, and every creation/deletion of an item updates the cache.
### Options
```
item_key The item name on the list table (like 'movie' for 'movie_id')
polymorphic Whether list table is polymorphic (list table contains 'item_id' and 'item_type')
add_method_name Name of method to add. Can be customized, for example 'like!' instead of 'add_like!'
remove_method_name Name of method to remove. Can be customized, for example 'unlike!' instead of 'removes_like!'
exists_method_name Name of method to check if exists. Can be customized, for example 'likes?' instead of 'has_like?'
reset_list_cache_method_name Reset cache, after manual insertion
class_name Name of class of list table, in case it's different than default
```