activerecord_cache 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +92 -0
- data/Rakefile +31 -1
- data/activerecord_cache.gemspec +1 -1
- data/lib/activerecord_cache.rb +1 -0
- data/lib/activerecord_cache/base.rb +2 -2
- data/lib/activerecord_cache/finder_methods.rb +3 -26
- data/lib/activerecord_cache/railtie.rb +4 -1
- data/lib/activerecord_cache/relation.rb +4 -6
- data/lib/activerecord_cache/version.rb +1 -1
- data/test/activerecord_cache_test.rb +167 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/models/associated_record.rb +3 -0
- data/test/dummy/app/models/cached_record.rb +3 -0
- data/test/dummy/app/models/non_primary_associated.rb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +55 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +39 -0
- data/test/dummy/config/environments/production.rb +70 -0
- data/test/dummy/config/environments/test.rb +33 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20140715044034_create_cached_records.rb +9 -0
- data/test/dummy/db/migrate/20140715052133_create_associated_records.rb +10 -0
- data/test/dummy/db/migrate/20140715053153_create_non_primary_associateds.rb +9 -0
- data/test/dummy/db/schema.rb +36 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/fixtures/associated_records.yml +9 -0
- data/test/dummy/test/fixtures/cached_records.yml +7 -0
- data/test/dummy/test/fixtures/non_primary_associateds.yml +9 -0
- data/test/dummy/test/unit/associated_record_test.rb +7 -0
- data/test/dummy/test/unit/cached_record_test.rb +7 -0
- data/test/dummy/test/unit/non_primary_associated_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- metadata +61 -27
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cc8aa7320c445aea2920adb2282e87eaf140c084
|
4
|
+
data.tar.gz: ef5d398cf49741e94e3b1073ba619e0c810559b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b57793fdef8d3b740e866bab4595401201f211e881b91e198c77c809ed99770b39563a059805745d374da2f2a5552efd6b3ddcf9384ed0d0a981cc70095fc66a
|
7
|
+
data.tar.gz: ccb1921116861244af6285ffaa82106f28279d8e7ac328521d30bad004a031ef877fd7a96266ec399ea8e20d492ea97fe70092bb4e54b451c0e096afd8ebb85d
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
activerecord_cache (0.0.7)
|
5
|
+
rails (~> 4.0.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
actionmailer (4.0.8)
|
11
|
+
actionpack (= 4.0.8)
|
12
|
+
mail (~> 2.5.4)
|
13
|
+
actionpack (4.0.8)
|
14
|
+
activesupport (= 4.0.8)
|
15
|
+
builder (~> 3.1.0)
|
16
|
+
erubis (~> 2.7.0)
|
17
|
+
rack (~> 1.5.2)
|
18
|
+
rack-test (~> 0.6.2)
|
19
|
+
activemodel (4.0.8)
|
20
|
+
activesupport (= 4.0.8)
|
21
|
+
builder (~> 3.1.0)
|
22
|
+
activerecord (4.0.8)
|
23
|
+
activemodel (= 4.0.8)
|
24
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
25
|
+
activesupport (= 4.0.8)
|
26
|
+
arel (~> 4.0.0)
|
27
|
+
activerecord-deprecated_finders (1.0.3)
|
28
|
+
activesupport (4.0.8)
|
29
|
+
i18n (~> 0.6, >= 0.6.9)
|
30
|
+
minitest (~> 4.2)
|
31
|
+
multi_json (~> 1.3)
|
32
|
+
thread_safe (~> 0.1)
|
33
|
+
tzinfo (~> 0.3.37)
|
34
|
+
arel (4.0.2)
|
35
|
+
bourne (1.5.0)
|
36
|
+
mocha (>= 0.13.2, < 0.15)
|
37
|
+
builder (3.1.4)
|
38
|
+
erubis (2.7.0)
|
39
|
+
hike (1.2.3)
|
40
|
+
i18n (0.6.11)
|
41
|
+
mail (2.5.4)
|
42
|
+
mime-types (~> 1.16)
|
43
|
+
treetop (~> 1.4.8)
|
44
|
+
metaclass (0.0.4)
|
45
|
+
mime-types (1.25.1)
|
46
|
+
minitest (4.7.5)
|
47
|
+
mocha (0.14.0)
|
48
|
+
metaclass (~> 0.0.1)
|
49
|
+
multi_json (1.10.1)
|
50
|
+
polyglot (0.3.5)
|
51
|
+
rack (1.5.2)
|
52
|
+
rack-test (0.6.2)
|
53
|
+
rack (>= 1.0)
|
54
|
+
rails (4.0.8)
|
55
|
+
actionmailer (= 4.0.8)
|
56
|
+
actionpack (= 4.0.8)
|
57
|
+
activerecord (= 4.0.8)
|
58
|
+
activesupport (= 4.0.8)
|
59
|
+
bundler (>= 1.3.0, < 2.0)
|
60
|
+
railties (= 4.0.8)
|
61
|
+
sprockets-rails (~> 2.0)
|
62
|
+
railties (4.0.8)
|
63
|
+
actionpack (= 4.0.8)
|
64
|
+
activesupport (= 4.0.8)
|
65
|
+
rake (>= 0.8.7)
|
66
|
+
thor (>= 0.18.1, < 2.0)
|
67
|
+
rake (10.3.2)
|
68
|
+
sprockets (2.12.1)
|
69
|
+
hike (~> 1.2)
|
70
|
+
multi_json (~> 1.0)
|
71
|
+
rack (~> 1.0)
|
72
|
+
tilt (~> 1.1, != 1.3.0)
|
73
|
+
sprockets-rails (2.1.3)
|
74
|
+
actionpack (>= 3.0)
|
75
|
+
activesupport (>= 3.0)
|
76
|
+
sprockets (~> 2.8)
|
77
|
+
sqlite3 (1.3.9)
|
78
|
+
thor (0.19.1)
|
79
|
+
thread_safe (0.3.4)
|
80
|
+
tilt (1.4.1)
|
81
|
+
treetop (1.4.15)
|
82
|
+
polyglot
|
83
|
+
polyglot (>= 0.3.1)
|
84
|
+
tzinfo (0.3.40)
|
85
|
+
|
86
|
+
PLATFORMS
|
87
|
+
ruby
|
88
|
+
|
89
|
+
DEPENDENCIES
|
90
|
+
activerecord_cache!
|
91
|
+
bourne
|
92
|
+
sqlite3
|
data/Rakefile
CHANGED
@@ -1,2 +1,32 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'TestPlugin'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
2
20
|
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
data/activerecord_cache.gemspec
CHANGED
data/lib/activerecord_cache.rb
CHANGED
@@ -6,5 +6,6 @@ require File.join(File.dirname(__FILE__), 'activerecord_cache/finder_methods')
|
|
6
6
|
require File.join(File.dirname(__FILE__), 'activerecord_cache/belongs_to_association')
|
7
7
|
require File.join(File.dirname(__FILE__), 'activerecord_cache/belongs_to_preloader')
|
8
8
|
require File.join(File.dirname(__FILE__), 'activerecord_cache/relation')
|
9
|
+
require File.join(File.dirname(__FILE__), 'activerecord_cache/errors')
|
9
10
|
|
10
11
|
require 'activerecord_cache/railtie.rb' if defined?(Rails)
|
@@ -14,7 +14,7 @@ module ActiveRecordCache
|
|
14
14
|
def cache_key(id_or_record)
|
15
15
|
unless use_activerecord_cache
|
16
16
|
message = "ActiveRecord cache is not enabled for #{self.name}"
|
17
|
-
raise ActiveRecordCache::
|
17
|
+
raise ActiveRecordCache::CacheNotEnabled, message
|
18
18
|
end
|
19
19
|
|
20
20
|
if id_or_record.is_a?(ActiveRecord::Base)
|
@@ -53,7 +53,7 @@ module ActiveRecordCache
|
|
53
53
|
end
|
54
54
|
|
55
55
|
if cache_misses.present?
|
56
|
-
records += where(primary_key => cache_misses).
|
56
|
+
records += where(primary_key => cache_misses).load
|
57
57
|
end
|
58
58
|
|
59
59
|
records
|
@@ -3,39 +3,18 @@ module ActiveRecordCache
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
alias_method_chain :find_by_attributes, :caching
|
7
6
|
alias_method_chain :find_some, :caching
|
8
7
|
alias_method_chain :find_one, :caching
|
9
8
|
end
|
10
9
|
|
11
10
|
protected
|
12
11
|
|
13
|
-
def find_by_attributes_with_caching(match, attributes, *args)
|
14
|
-
unless cached_lookup_allowed? && attributes == Array(@klass.primary_key) && (match.finder == :all || !args.first.is_a?(Array))
|
15
|
-
return find_by_attributes_without_caching(match, attributes, *args)
|
16
|
-
end
|
17
|
-
|
18
|
-
param = args.first
|
19
|
-
|
20
|
-
results = case match.finder
|
21
|
-
when :all then @klass.find_some_through_cache(Array(param))
|
22
|
-
when :first then @klass.find_through_cache(param)
|
23
|
-
when :last then @klass.find_through_cache(param)
|
24
|
-
end
|
25
|
-
|
26
|
-
results
|
27
|
-
end
|
28
|
-
|
29
12
|
def find_some_with_caching(ids)
|
30
13
|
return find_some_without_caching(ids) unless cached_lookup_allowed?
|
31
14
|
|
32
15
|
results = find_some_through_cache(ids)
|
33
16
|
|
34
|
-
|
35
|
-
error = "Couldn't find all #{@klass.name.pluralize} with IDs "
|
36
|
-
error << "(#{ids.join(", ")}) (found #{results.size} results, but was looking for #{ids.size})"
|
37
|
-
raise ActiveRecord::RecordNotFound, error
|
38
|
-
end
|
17
|
+
raise_record_not_found_exception!(ids, result.size, ids.size) unless results.size == ids.size
|
39
18
|
|
40
19
|
results
|
41
20
|
end
|
@@ -43,11 +22,9 @@ module ActiveRecordCache
|
|
43
22
|
def find_one_with_caching(id)
|
44
23
|
return find_one_without_caching(id) unless cached_lookup_allowed?
|
45
24
|
|
46
|
-
record =
|
25
|
+
record = find_through_cache(id)
|
47
26
|
|
48
|
-
unless record
|
49
|
-
raise ActiveRecord::RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}"
|
50
|
-
end
|
27
|
+
raise_record_not_found_exception!(id, 0, 1) unless record
|
51
28
|
|
52
29
|
record
|
53
30
|
end
|
@@ -6,10 +6,13 @@ class ActiveRecordCache::Railtie < Rails::Railtie
|
|
6
6
|
initializer "activerecord_cache.initialize" do
|
7
7
|
ActiveSupport.on_load(:active_record) do
|
8
8
|
ActiveRecord::Base.send(:include, ActiveRecordCache::Base)
|
9
|
-
ActiveRecord::FinderMethods.send(:include, ActiveRecordCache::FinderMethods)
|
10
9
|
ActiveRecord::Associations::BelongsToAssociation.send(:include, ActiveRecordCache::BelongsToAssociation)
|
11
10
|
ActiveRecord::Associations::Preloader::BelongsTo.send(:include, ActiveRecordCache::BelongsToPreloader)
|
12
11
|
ActiveRecord::Relation.send(:include, ActiveRecordCache::Relation)
|
12
|
+
|
13
|
+
# FinderMethods only gets included in ActiveRecord::Relation, so extend it there.
|
14
|
+
# This gets around some headaches caused by extending modules already included in other classes.
|
15
|
+
ActiveRecord::Relation.send(:include, ActiveRecordCache::FinderMethods)
|
13
16
|
end
|
14
17
|
end
|
15
18
|
|
@@ -3,14 +3,12 @@ module ActiveRecordCache
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
alias_method_chain :
|
6
|
+
alias_method_chain :exec_queries, :caching
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
records = to_a_without_caching
|
13
|
-
records.each(&:write_to_cache) if @klass.use_activerecord_cache && !previously_loaded && select_values.empty?
|
9
|
+
def exec_queries_with_caching
|
10
|
+
records = exec_queries_without_caching
|
11
|
+
records.each(&:write_to_cache) if @klass.use_activerecord_cache && select_values.empty?
|
14
12
|
|
15
13
|
records
|
16
14
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveRecordCacheTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
setup do
|
6
|
+
Rails.cache.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
# Loading records should persist to cache
|
12
|
+
test "loading records using find should persist them to the cache" do
|
13
|
+
Rails.cache.expects(:write).twice
|
14
|
+
CachedRecord.find(1, 2)
|
15
|
+
end
|
16
|
+
|
17
|
+
test "loading all records should persist them to the cache" do
|
18
|
+
Rails.cache.expects(:write).twice
|
19
|
+
CachedRecord.all.load
|
20
|
+
end
|
21
|
+
|
22
|
+
test "loading records using a where should persist them to the cache" do
|
23
|
+
Rails.cache.expects(:write).once
|
24
|
+
CachedRecord.where(:name => 'John').load
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
# Finders should use the cache
|
30
|
+
test "#find(id) should use the cache" do
|
31
|
+
cache_records(1)
|
32
|
+
|
33
|
+
assert_query_count 0 do
|
34
|
+
CachedRecord.find(1)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
test "#find(ids) should use the cache" do
|
39
|
+
cache_records(1,2)
|
40
|
+
|
41
|
+
assert_query_count 0 do
|
42
|
+
CachedRecord.find(1, 2)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
test "#find(ids) with some cached records should query for additional records" do
|
47
|
+
cache_records(1)
|
48
|
+
|
49
|
+
assert_query_count 1 do
|
50
|
+
CachedRecord.find(1, 2)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
# Complex queries should skip the cache
|
57
|
+
test "#where(:id => id, :other => criteria) should NOT use the cache" do
|
58
|
+
cache_records(1)
|
59
|
+
|
60
|
+
records = CachedRecord.where(:id => 1, :name => 'Bogus').load
|
61
|
+
|
62
|
+
assert records.empty?, 'should not find cached record'
|
63
|
+
end
|
64
|
+
|
65
|
+
test "#select(:id) should NOT use the cache" do
|
66
|
+
cache_records(1)
|
67
|
+
|
68
|
+
Rails.cache.expects(:write).never
|
69
|
+
CachedRecord.select(:id).load
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
# belongs_to associations should use the cache
|
75
|
+
test "accessing cached associations should use the cache" do
|
76
|
+
cache_records(1)
|
77
|
+
associated = AssociatedRecord.find(1)
|
78
|
+
|
79
|
+
assert_query_count 0 do
|
80
|
+
associated.cached_record
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
test "accessing associations should persist records to the cache" do
|
85
|
+
associated = AssociatedRecord.find(1)
|
86
|
+
|
87
|
+
Rails.cache.expects(:write).once
|
88
|
+
associated.cached_record
|
89
|
+
end
|
90
|
+
|
91
|
+
test "associations that do not reference the primary key should NOT use the cache" do
|
92
|
+
cache_records(1, 2)
|
93
|
+
non_primary = NonPrimaryAssociated.find(1)
|
94
|
+
|
95
|
+
assert_query_count 1 do
|
96
|
+
non_primary.cached_record
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
# Preloading associations should use the cache
|
103
|
+
test "preloading associations should use the cache" do
|
104
|
+
cache_records(1)
|
105
|
+
|
106
|
+
assert_query_count 1 do
|
107
|
+
AssociatedRecord.includes(:cached_record).find(1)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
test "preloading associations should persist records to the cache" do
|
112
|
+
Rails.cache.expects(:write).once
|
113
|
+
AssociatedRecord.includes(:cached_record).find(1)
|
114
|
+
end
|
115
|
+
|
116
|
+
test "preloading associations that do not reference the primary key should NOT use the cache" do
|
117
|
+
cache_records(1, 2)
|
118
|
+
|
119
|
+
assert_query_count 2 do
|
120
|
+
NonPrimaryAssociated.includes(:cached_record).find(1)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
# Saving and destroying
|
127
|
+
test "saving a record should write it to the cache" do
|
128
|
+
Rails.cache.expects(:write).once
|
129
|
+
CachedRecord.create!({})
|
130
|
+
end
|
131
|
+
|
132
|
+
test "destroying a record should remove it from the cache" do
|
133
|
+
Rails.cache.expects(:delete).once
|
134
|
+
CachedRecord.find(1).destroy
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
def assert_query_count(expected_count, &block)
|
142
|
+
count = count_queries do
|
143
|
+
yield block
|
144
|
+
end
|
145
|
+
|
146
|
+
assert_equal expected_count, count, "expected #{expected_count} queries"
|
147
|
+
end
|
148
|
+
|
149
|
+
def count_queries(&block)
|
150
|
+
count = 0
|
151
|
+
|
152
|
+
counter = ->(name, started, finished, unique_id, payload) {
|
153
|
+
unless payload[:name].in? %w[ CACHE SCHEMA ]
|
154
|
+
count += 1
|
155
|
+
end
|
156
|
+
}
|
157
|
+
|
158
|
+
ActiveSupport::Notifications.subscribed(counter, "sql.active_record", &block)
|
159
|
+
|
160
|
+
count
|
161
|
+
end
|
162
|
+
|
163
|
+
def cache_records(*records)
|
164
|
+
CachedRecord.find(Array(records).flatten)
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|