{"id":13483179,"url":"https://github.com/hooopo/second_level_cache","last_synced_at":"2025-04-08T10:17:34.157Z","repository":{"id":1800932,"uuid":"2724927","full_name":"hooopo/second_level_cache","owner":"hooopo","description":"Write Through and Read Through caching library inspired by CacheMoney and cache_fu, support ActiveRecord 4, 5 and 6.","archived":false,"fork":false,"pushed_at":"2022-02-15T00:18:24.000Z","size":865,"stargazers_count":394,"open_issues_count":5,"forks_count":90,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-01T08:42:32.094Z","etag":null,"topics":["activerecord","activerecord5","cache","cache-money","rails","rails5","rails6"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"cresprit/mqttbot","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hooopo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-11-07T08:43:10.000Z","updated_at":"2025-03-31T14:30:40.000Z","dependencies_parsed_at":"2022-08-20T17:10:20.973Z","dependency_job_id":null,"html_url":"https://github.com/hooopo/second_level_cache","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hooopo%2Fsecond_level_cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hooopo%2Fsecond_level_cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hooopo%2Fsecond_level_cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hooopo%2Fsecond_level_cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hooopo","download_url":"https://codeload.github.com/hooopo/second_level_cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247819940,"owners_count":21001394,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","activerecord5","cache","cache-money","rails","rails5","rails6"],"created_at":"2024-07-31T17:01:08.843Z","updated_at":"2025-04-08T10:17:34.137Z","avatar_url":"https://github.com/hooopo.png","language":"Ruby","readme":"# SecondLevelCache\n\n[![Gem Version](https://badge.fury.io/rb/second_level_cache.svg)](http://badge.fury.io/rb/second_level_cache)\n[![build](https://github.com/hooopo/second_level_cache/actions/workflows/build.yml/badge.svg)](https://github.com/hooopo/second_level_cache/actions/workflows/build.yml)\n[![Code Climate](https://codeclimate.com/github/hooopo/second_level_cache.svg)](https://codeclimate.com/github/hooopo/second_level_cache)\n\nSecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support ActiveRecord 4, ActiveRecord 5 and ActiveRecord 6.\n\nRead-Through: Queries by ID, like `current_user.articles.find(params[:id])`, will first look in cache store and then look in the database for the results of that query. If there is a cache miss, it will populate the cache.\n\nWrite-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.\n\n## Install\n\nIn your gem file:\n\nActiveRecord 7\n\n```ruby\ngem 'second_level_cache', '~\u003e 2.7'\n```\n\nActiveRecord 5.2 and 6.0:\n\n```ruby\ngem 'second_level_cache', '~\u003e 2.6.3'\n```\n\nActiveRecord 5.0.x, 5.1.x:\n\n```ruby\ngem 'second_level_cache', '~\u003e 2.3.0'\n```\n\nFor ActiveRecord 4:\n\n```ruby\ngem \"second_level_cache\", \"~\u003e 2.1.9\"\n```\n\nFor ActiveRecord 3:\n\n```ruby\ngem \"second_level_cache\", \"~\u003e 1.6\"\n```\n\n## Usage\n\nFor example, cache User objects:\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  second_level_cache expires_in: 1.week\nend\n```\n\nThen it will fetch cached object in this situations:\n\n```ruby\nUser.find(1)\nuser.articles.find(1)\nUser.where(status: 1).find(1)\nUser.where(id: 1).first # or .last\narticle.user\n```\n\nCache key:\n\n```ruby\nuser = User.find(1)\nuser.second_level_cache_key  # We will get the key looks like \"slc/user/1/0\"\n```\n\nExpires cache:\n\n```ruby\nuser = User.find(1)\nuser.expire_second_level_cache\n```\n\nor expires cache using class method:\n\n```ruby\nUser.expire_second_level_cache(1)\n```\n\nDisable SecondLevelCache:\n\n```ruby\nUser.without_second_level_cache do\n  user = User.find(1)\n  # ...\nend\n```\n\nOnly `SELECT *` query will be cached:\n\n```ruby\n# this query will NOT be cached\nUser.select(\"id, name\").find(1)\n```\n\n## Notice\n\n- SecondLevelCache cache by model name and id, so only find_one query will work.\n- Only equal conditions query WILL get cache; and SQL string query like `User.where(\"name = 'Hooopo'\").find(1)` WILL NOT work.\n- SecondLevelCache sync cache after transaction commit:\n\n```ruby\n# user and account's write_second_level_cache operation will invoke after the logger.\nActiveRecord::Base.transaction do\n  user.save\n  account.save\n  Rails.logger.info \"info\"\nend # \u003c- Cache write\n\n# if you want to do something after user and account's write_second_level_cache operation, do this way:\nActiveRecord::Base.transaction do\n  user.save\n  account.save\nend # \u003c- Cache write\nRails.logger.info \"info\"\n```\n\n- If you are using SecondLevelCache with database_cleaner, you should set cleaning strategy to `:truncation`:\n\n```ruby\nDatabaseCleaner.strategy = :truncation\n```\n\n## Configure\n\nIn production env, we recommend to use [Dalli](https://github.com/mperham/dalli) as Rails cache store.\n\n```ruby\nconfig.cache_store = [:dalli_store, APP_CONFIG[\"memcached_host\"], { namespace: \"ns\", compress: true }]\n```\n\n## Tips:\n\n- When you want to clear only second level cache apart from other cache for example fragment cache in cache store,\n  you can only change the `cache_key_prefix` (default: `slc`):\n\n```ruby\nSecondLevelCache.configure.cache_key_prefix = \"slc1\"\n```\n\n- SecondLevelCache was added model schema digest as cache version, this means when you add/remove/change columns, the caches of this Model will expires.\n- When your want change the model cache version by manualy, just add the `version` option like this:\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  second_level_cache version: 2, expires_in: 1.week\nend\n```\n\n- It provides a great feature, not hits db when fetching record via unique key (not primary key).\n\n```ruby\n# this will fetch from cache\nuser = User.fetch_by_uniq_keys(nick_name: \"hooopo\")\npost = Post.fetch_by_uniq_keys(user_id: 2, slug: \"foo\")\n\n# this also fetch from cache\nuser = User.fetch_by_uniq_keys!(nick_name: \"hooopo\") # this will raise `ActiveRecord::RecordNotFound` Exception when nick name not exists.\n```\n\n- You can use Rails's [Eager Loading](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) feature as normal. Even better, second_level_cache will transform the `IN` query into a Rails.cache.multi_read operation. For example:\n\n```ruby\nAnswer.includes(:question).limit(10).order(\"id DESC\").each{|answer| answer.question.title}\nAnswer Load (0.2ms)  SELECT `answers`.* FROM `answers` ORDER BY id DESC LIMIT 10 # Only one SQL query and one Rails.cache.read_multi fetching operation.\n```\n\n[Details for read_multi feature](http://hooopo.writings.io/articles/a9cae5e0).\n\n## Original design by:\n\n- [chloerei](https://github.com/chloerei)\n- [hooopo](https://github.com/hooopo)\n\n## Contributors\n\n[Contributor List](https://github.com/hooopo/second_level_cache/graphs/contributors)\n\n## License\n\nMIT License\n","funding_links":[],"categories":["Ruby","Caching"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhooopo%2Fsecond_level_cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhooopo%2Fsecond_level_cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhooopo%2Fsecond_level_cache/lists"}