ActiveCash
Drop in cache strategies for ActiveRecord.
I named the gem ActiveCash in case an official gem arrives with the name ActiveCache.
Installation
Add this line to your application's Gemfile:
gem 'active_cash'
And then execute:
$ bundle
Or install it yourself as:
$ gem install active_cash
Usage
We will add more strategies soon..
Existence strategy
class Like < ActiveRecord::Base
include ActiveCash
# type # matched conditions # cache name (default is strategy name)
caches :existence, find_by: [:user_id, :video_id]
caches :existence, find_by: [:user_id, :video_id, :hidden], as: :hidden #also name: :hidden is supported
end
# Check if Like exists for specific :user_id, :video_id.
@like = Like.cached_existence_by(user_id: 1, video_id: 2)
# Check if a hidden Like exists for specific :user_id, :video_id.
# not sure what hidden could be but let's say that likes table has a boolean hidden column :)
@like = Like.cached_hidden_by(user_id: 1, video_id: 2, hidden: true)
I am open for better naming conventions :)
Cache will be created and updated on every object creation, update and deletion
using an after_commit
callback. Only a string value is saved (true or false)
in Redis (using redis-objects underneath)
making it extremely efficient.
If you want to have a read-driven cache (which could
enhance your hit ratio depending on your read/writes ratio) you can provide an
empty update_on
array (by default it includes [:create, :update, :destroy]
):
class Like < ActiveRecord::Base
include ActiveCash
# type # matched conditions # updating strategies
caches :existence, find_by: [:video_id], update_on: []
end
# Check if Like exists for specific :user_id, :video_id.
@like = Like.cached_existence_by(user_id: 1, video_id: 2)
# Check if a hidden Like exists for specific :user_id, :video_id.
# not sure what hidden could be but let's say that likes table has a boolean hidden column :)
@like = Like.cached_hidden_by(user_id: 1, video_id: 2, hidden: true)
Now cache will be created and updated ONLY IF there is a reference to Redis.
You can also specify the return value (the symbol must be a method defined in the class instance):
class Like < ActiveRecord::Base
include ActiveCash
caches :existence, find_by: [:user_id, :video_id, :state], as: :state, returns: :state
end
# Check if Like exists for specific :user_id, :video_id.
# returns the state
# returns false if state.nil?
@like = Like.cached_existence_by(user_id: 1, video_id: 2)
Not though that cache will return false if state is nil.
Todo
Only existence strategy is supported at the moment but the code is designed to support other kind of caching strategies as well, like caching the whole object or some parts of it. Also:
- Refactor a bit :(
- We should provide named callbacks
- It's super easy to extend for Mongoid
- Add memcached adapter
Relevant projects
There is identity_cache built by Shopify. It uses memcached unfortunately that's why I needed something else. For existence strategy ActiveCash is definitely better when it comes to space optimizations. But I would use that if I wanted a full bloated solution.
Unfortunately I couldn't find any other gem for database caching :(
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
to create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
- Fork it ( https://github.com/vasilakisfil/active_cash/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request