Skip to content

Commit

Permalink
Merge pull request #131 from hooopo/feat/rails-7
Browse files Browse the repository at this point in the history
Switch to GitHub Actions
  • Loading branch information
huacnlee authored Dec 17, 2021
2 parents f69eadc + d911ef9 commit d8b271b
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 60 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: build
on: push
jobs:
build:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- ruby: 3.0
gemfile: Gemfile
- ruby: 2.7
gemfile: gemfiles/Gemfile-6-1
- ruby: 2.7
gemfile: gemfiles/Gemfile-6-0-paranoia
- ruby: 2.6
gemfile: gemfiles/Gemfile-6-0
- ruby: 2.6
gemfile: gemfiles/Gemfile-5-2
env:
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
USE_OFFICIAL_GEM_SOURCE: 1
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: bundle exec rake test
17 changes: 0 additions & 17 deletions .travis.yml

This file was deleted.

File renamed without changes.
33 changes: 19 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SecondLevelCache

[![Gem Version](https://badge.fury.io/rb/second_level_cache.svg)](http://badge.fury.io/rb/second_level_cache)
[![Build Status](https://travis-ci.org/hooopo/second_level_cache.svg?branch=master)](https://travis-ci.org/hooopo/second_level_cache)
[![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)
[![Code Climate](https://codeclimate.com/github/hooopo/second_level_cache.svg)](https://codeclimate.com/github/hooopo/second_level_cache)

SecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support ActiveRecord 4, ActiveRecord 5 and ActiveRecord 6.
Expand All @@ -10,11 +10,16 @@ Read-Through: Queries by ID, like `current_user.articles.find(params[:id])`, wil

Write-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.


## Install

In your gem file:

ActiveRecord 7

```ruby
gem 'second_level_cache', '~> 2.7'
```

ActiveRecord 5.2 and 6.0:

```ruby
Expand Down Expand Up @@ -97,9 +102,9 @@ User.select("id, name").find(1)

## Notice

* SecondLevelCache cache by model name and id, so only find_one query will work.
* Only equal conditions query WILL get cache; and SQL string query like `User.where("name = 'Hooopo'").find(1)` WILL NOT work.
* SecondLevelCache sync cache after transaction commit:
- SecondLevelCache cache by model name and id, so only find_one query will work.
- Only equal conditions query WILL get cache; and SQL string query like `User.where("name = 'Hooopo'").find(1)` WILL NOT work.
- SecondLevelCache sync cache after transaction commit:

```ruby
# user and account's write_second_level_cache operation will invoke after the logger.
Expand All @@ -117,7 +122,7 @@ end # <- Cache write
Rails.logger.info "info"
```

* If you are using SecondLevelCache with database_cleaner, you should set cleaning strategy to `:truncation`:
- If you are using SecondLevelCache with database_cleaner, you should set cleaning strategy to `:truncation`:

```ruby
DatabaseCleaner.strategy = :truncation
Expand All @@ -133,23 +138,23 @@ config.cache_store = [:dalli_store, APP_CONFIG["memcached_host"], { namespace: "

## Tips:

* When you want to clear only second level cache apart from other cache for example fragment cache in cache store,
you can only change the `cache_key_prefix` (default: `slc`):
- When you want to clear only second level cache apart from other cache for example fragment cache in cache store,
you can only change the `cache_key_prefix` (default: `slc`):

```ruby
SecondLevelCache.configure.cache_key_prefix = "slc1"
```

* SecondLevelCache was added model schema digest as cache version, this means when you add/remove/change columns, the caches of this Model will expires.
* When your want change the model cache version by manualy, just add the `version` option like this:
- SecondLevelCache was added model schema digest as cache version, this means when you add/remove/change columns, the caches of this Model will expires.
- When your want change the model cache version by manualy, just add the `version` option like this:

```ruby
class User < ActiveRecord::Base
second_level_cache version: 2, expires_in: 1.week
end
```

* It provides a great feature, not hits db when fetching record via unique key (not primary key).
- It provides a great feature, not hits db when fetching record via unique key (not primary key).

```ruby
# this will fetch from cache
Expand All @@ -160,7 +165,7 @@ post = Post.fetch_by_uniq_keys(user_id: 2, slug: "foo")
user = User.fetch_by_uniq_keys!(nick_name: "hooopo") # this will raise `ActiveRecord::RecordNotFound` Exception when nick name not exists.
```

* 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:
- 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:

```ruby
Answer.includes(:question).limit(10).order("id DESC").each{|answer| answer.question.title}
Expand All @@ -171,8 +176,8 @@ Answer Load (0.2ms) SELECT `answers`.* FROM `answers` ORDER BY id DESC LIMIT 10

## Original design by:

* [chloerei](https://github.com/chloerei)
* [hooopo](https://github.com/hooopo)
- [chloerei](https://github.com/chloerei)
- [hooopo](https://github.com/hooopo)

## Contributors

Expand Down
7 changes: 0 additions & 7 deletions gemfiles/Gemfile-edge

This file was deleted.

31 changes: 16 additions & 15 deletions lib/second_level_cache/active_record/fetch_by_uniq_key.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ def fetch_by_uniq_keys(where_values)

if obj_id
record = begin
find(obj_id)
rescue StandardError
nil
end
find(obj_id)
rescue
nil
end
end
return record if record_attributes_equal_where_values?(record, where_values)
record = where(where_values).first
Expand Down Expand Up @@ -42,20 +42,21 @@ def fetch_by_uniq_key!(value, uniq_key_name)
end

private
def cache_uniq_key(where_values)
keys = where_values.collect do |k, v|
v = Digest::MD5.hexdigest(v) if v.respond_to?(:size) && v.size >= 32
[k, v].join("_")
end

ext_key = keys.join(",")
"#{SecondLevelCache.configure.cache_key_prefix}/uniq_key_#{name}_#{ext_key}"
def cache_uniq_key(where_values)
keys = where_values.collect do |k, v|
v = Digest::MD5.hexdigest(v) if v.respond_to?(:size) && v.size >= 32
[k, v].join("_")
end

def record_attributes_equal_where_values?(record, where_values)
# https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-type_for_attribute
where_values.all? { |k, v| record&.read_attribute(k) == type_for_attribute(k).cast(v) }
end
ext_key = keys.join(",")
"#{SecondLevelCache.configure.cache_key_prefix}/uniq_key_#{name}_#{ext_key}"
end

def record_attributes_equal_where_values?(record, where_values)
# https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-type_for_attribute
where_values.all? { |k, v| record&.read_attribute(k) == type_for_attribute(k).cast(v) }
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ module ActiveRecord
module Associations
module Preloader
module Association
# In Rails 7, override load_query for assign self
# Override load_query method for add Association instance in arguments to LoaderQuery
# https://github.com/rails/rails/blob/7-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L148
def loader_query
::ActiveRecord::Associations::Preloader::Association::LoaderQuery.new(self, scope, association_key_name)
end

# Override load_records_for_keys for use SecondLevelCache before preload association
# https://github.com/rails/rails/blob/8f5b35b6107c28125b571b9842e248b13f804e5c/activerecord/lib/active_record/associations/preloader/association.rb#L7
module LoaderQuery
attr_reader :association

Expand Down
8 changes: 4 additions & 4 deletions lib/second_level_cache/active_record/preloader/legacy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ def records_for(ids, &block)

SecondLevelCache::RecordRelation.new(records_from_db + record_marshals)
end
end

private
private

def write_cache(record)
record.write_second_level_cache
def write_cache(record)
record.write_second_level_cache
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions second_level_cache.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Gem::Specification.new do |gem|

gem.files = Dir.glob("lib/**/*.rb") + [
"README.md",
"LICENSE",
"Rakefile",
"Gemfile",
"CHANGELOG.md",
Expand Down
3 changes: 1 addition & 2 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

require "bundler/setup"
require "minitest/autorun"
require "active_support/isolated_execution_state"
require "active_support/test_case"
require "active_support/all"
require "active_record_test_case_helper"
require "database_cleaner"
require "active_record"
Expand Down

0 comments on commit d8b271b

Please sign in to comment.