thermos 1.0.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +213 -0
- data/lib/thermos/version.rb +1 -1
- data/test/dependencies_test.rb +19 -19
- data/test/dummy/app/models/category.rb +1 -1
- data/test/dummy/app/models/category_item.rb +2 -2
- data/test/dummy/config/application.rb +20 -7
- data/test/dummy/config/environments/development.rb +11 -19
- data/test/dummy/config/environments/production.rb +9 -61
- data/test/dummy/config/environments/test.rb +20 -23
- data/test/dummy/db/schema.rb +6 -6
- data/test/filter_test.rb +3 -3
- data/test/test_helper.rb +2 -2
- data/test/thermos_test.rb +5 -5
- metadata +42 -28
- data/test/dummy/config/initializers/session_store.rb +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96c092c9b446b9147dca86d7f6b655dcb8f6f00191a8260b0dbb6bd15bea56c1
|
|
4
|
+
data.tar.gz: e7b19005dffe9c4fbec290576e0d9094fb1d04021fd037e3148dc7bb57d99179
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5484c23bf0c7ff96d75158c37bc399cf06a45a25447347c2a56ffc0bc8d026742042655019dbfb3518fbb3ea9765431963db334973692e3ad4f9cf272c78710e
|
|
7
|
+
data.tar.gz: 39f11866f8de933f2e6f68174f43d4c4b88fc48b25c472bee5799447cdcc6d91c568eb31173bf004a41cccf0d0b882cd0368d299287b6487d2c6f7d99bccac8c
|
data/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Thermos
|
|
2
|
+
|
|
3
|
+
**Always-warm Rails caching that automatically rebuilds when your models change.**
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/rb/thermos)
|
|
6
|
+
[](https://codeclimate.com/github/athal7/thermos)
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
Thermos is a Rails caching library that keeps your cache always warm by rebuilding it in the background whenever ActiveRecord models change. No more stale data, no more cold cache penalties, no more `touch: true` on all your associations.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Always-warm cache** — Cache is rebuilt in the background when models change
|
|
14
|
+
- **No stale data** — Unlike TTL-based caching, data is only as stale as your job queue latency
|
|
15
|
+
- **No cold cache penalties** — Cache is pre-warmed, so users never wait for expensive queries
|
|
16
|
+
- **No `touch` callbacks needed** — Thermos watches model dependencies automatically
|
|
17
|
+
- **Works with any backend** — Sidekiq, Solid Queue, Resque, or any ActiveJob adapter
|
|
18
|
+
- **Works with any cache store** — Redis, Memcached, Solid Cache, or any Rails cache store
|
|
19
|
+
- **ETag support** — Works seamlessly with HTTP caching for browser and CDN caching
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Add to your Gemfile:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem 'thermos'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then run:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bundle install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# In a controller - cache is automatically rebuilt when Category or its products change
|
|
39
|
+
json = Thermos.keep_warm(key: "category", model: Category, id: params[:id], deps: [:products]) do |id|
|
|
40
|
+
Category.includes(:products).find(id).to_json
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
render json: json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
That's it! When any `Category` or associated `Product` is created, updated, or destroyed, Thermos automatically rebuilds the cache in the background.
|
|
47
|
+
|
|
48
|
+
## Why Thermos?
|
|
49
|
+
|
|
50
|
+
Most cache strategies have significant downsides:
|
|
51
|
+
|
|
52
|
+
| Strategy | Problem |
|
|
53
|
+
|----------|---------|
|
|
54
|
+
| **TTL-based** (expires_in) | Stale data until expiration |
|
|
55
|
+
| **Key-based** (cache_key) | Cold cache on first request after any change |
|
|
56
|
+
| **Touch callbacks** | Extra database writes on every association change |
|
|
57
|
+
|
|
58
|
+
Thermos solves all of these by rebuilding caches proactively in background jobs.
|
|
59
|
+
|
|
60
|
+
> "I just want to Thermos everything now!! Unbelievable improvement. It's like every dev's dream come true" — [@jono-booth](https://github.com/jono-booth)
|
|
61
|
+
|
|
62
|
+
## Prerequisites
|
|
63
|
+
|
|
64
|
+
Configure a [Rails Cache Store](https://guides.rubyonrails.org/caching_with_rails.html#configuration) that supports shared access across processes (Redis, Memcached, Solid Cache — not MemoryStore).
|
|
65
|
+
|
|
66
|
+
Thermos works with any ActiveJob adapter, including Rails 8's [Solid Queue](https://github.com/rails/solid_queue) and [Solid Cache](https://github.com/rails/solid_cache).
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
69
|
+
|
|
70
|
+
### keep_warm (Simple)
|
|
71
|
+
|
|
72
|
+
With `keep_warm`, the cached content is defined along with the cache block and dependencies definition. This is the simplest implementation, *but is only compatible with the [Active Job Inline Adapter](https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html)*. See the next section about fill/drink for compatibility with other Active Job Adapters.
|
|
73
|
+
|
|
74
|
+
*API Controller*
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
json = Thermos.keep_warm(key: "api_categories_show", model: Category, id: params[:id], deps: [:category_items, :products]) do |id|
|
|
78
|
+
Category.find(id).to_json
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
render json: json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
*Frontend Controller*
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
rendered_template = Thermos.keep_warm(key: "frontend_categories_show", model: Category, id: params[:id], deps: [:category_items, :products]) do |id|
|
|
88
|
+
@category = Category.includes(category_items: :product).find(id)
|
|
89
|
+
render_to_string :show
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
render rendered_template
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### fill / drink (Advanced)
|
|
96
|
+
|
|
97
|
+
For more control, define your cache once with `fill` and read it anywhere with `drink`. This is ideal for sharing cached data across multiple controllers or when using background job adapters other than inline.
|
|
98
|
+
|
|
99
|
+
*Rails Initializer*
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
Thermos.fill(key: "api_categories_show", model: Category, deps: [:category_items, :products]) do |id|
|
|
103
|
+
Category.find(id).to_json
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
*API Controller*
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
json = Thermos.drink(key: "api_categories_show", id: params[:id])
|
|
111
|
+
render json: json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Options
|
|
115
|
+
|
|
116
|
+
### lookup_key
|
|
117
|
+
|
|
118
|
+
If you want to be able to lookup by a key other than `id` (e.g. you use a slug in the params), you can specify the `lookup_key` as an argument to `keep_warm` or `fill`:
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
Thermos.keep_warm(key: "api_categories_show", model: Category, id: params[:slug], lookup_key: :slug) do |slug|
|
|
122
|
+
Category.find_by(slug: slug).to_json
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
or
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
Thermos.fill(key: "api_categories_show", model: Category, lookup_key: :slug) do |slug|
|
|
130
|
+
Category.find_by(slug: slug).to_json
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### queue
|
|
135
|
+
|
|
136
|
+
If you want to specify a queue for the refill jobs to run other than the default queue, you can provide it to either way of using Thermos:
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
Thermos.keep_warm(key: "api_categories_show", model: Category, queue: "low_priority") do |id|
|
|
140
|
+
Category.find(id).to_json
|
|
141
|
+
end
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
or
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
Thermos.fill(key: "api_categories_show", model: Category, queue: "low_priority") do |id|
|
|
148
|
+
Category.find(id).to_json
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
Thermos.drink(key: "api_categories_show", id: params[:slug])
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Indirect Relationships
|
|
155
|
+
|
|
156
|
+
You can specify indirect relationships as dependencies as well. For example, if `Store has_many categories`, and `Category has_many products`, but there is no relationship specified on the `Store` model to `Product`:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
Thermos.keep_warm(key: "api_stores_show", model: Store, id: params[:id], deps: [categories: [:products]]) do |id|
|
|
160
|
+
Store.find(id).to_json
|
|
161
|
+
end
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
*NOTE* in this example, a change to any model in the association chain will trigger a refill of the cache.
|
|
165
|
+
|
|
166
|
+
### filter
|
|
167
|
+
|
|
168
|
+
You can provide a filter to restrict whether a record gets rebuilt on model changes:
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
filter = ->(model) { model.name.match("ball") }
|
|
172
|
+
Thermos.keep_warm(key: "api_categories_show", model: Category, id: params[:id], filter: filter) do |id|
|
|
173
|
+
Category.find(id).to_json
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Using with ETags
|
|
178
|
+
|
|
179
|
+
Thermos works seamlessly with Rails' HTTP caching via ETags, enabling browser and CDN caching of your responses. Since Thermos keeps your cache always warm and rebuilds it when models change, the cached value's digest will naturally change when the underlying data changes.
|
|
180
|
+
|
|
181
|
+
Use Rails' `stale?` helper with the cached value to enable conditional GET requests:
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
def show
|
|
185
|
+
json = Thermos.drink(key: "api_categories_show", id: params[:id])
|
|
186
|
+
|
|
187
|
+
if stale?(etag: json)
|
|
188
|
+
render json: json
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
When the cached value changes (triggered by model updates), the ETag will change, and clients will receive the new content. When the value hasn't changed, clients with a matching ETag will receive a `304 Not Modified` response.
|
|
194
|
+
|
|
195
|
+
This enables caching at multiple layers:
|
|
196
|
+
- **Browser cache**: Browsers store responses and revalidate with the server using the ETag, avoiding re-downloads of unchanged content
|
|
197
|
+
- **CDN cache**: CDNs can cache responses and serve them directly to users, only revalidating with your server when needed
|
|
198
|
+
|
|
199
|
+
Combined with Thermos, you get:
|
|
200
|
+
- **Always-warm application cache** (no cold cache penalties)
|
|
201
|
+
- **Reduced server load** (304 responses skip rendering)
|
|
202
|
+
- **Reduced bandwidth** (browsers and CDNs serve cached content)
|
|
203
|
+
- **Faster responses** (CDN edge locations serve content closer to users)
|
|
204
|
+
|
|
205
|
+
## Contributors
|
|
206
|
+
|
|
207
|
+
<a href="https://github.com/athal7/thermos/graphs/contributors">
|
|
208
|
+
<img src="https://contrib.rocks/image?repo=athal7/thermos" />
|
|
209
|
+
</a>
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
This project uses MIT-LICENSE.
|
data/lib/thermos/version.rb
CHANGED
data/test/dependencies_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
2
|
|
|
3
|
-
class DependenciesTest <
|
|
3
|
+
class DependenciesTest < ActiveJob::TestCase
|
|
4
4
|
self.use_transactional_tests = true
|
|
5
5
|
teardown :clear_cache
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
18
18
|
mock.verify
|
|
19
19
|
|
|
20
20
|
mock.expect(:call, 2, [category.id])
|
|
21
|
-
category_item.update!(name: "foo")
|
|
21
|
+
perform_enqueued_jobs { category_item.update!(name: "foo") }
|
|
22
22
|
mock.verify
|
|
23
23
|
|
|
24
24
|
mock.expect(:call, 3, [category.id])
|
|
@@ -40,7 +40,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
40
40
|
mock.verify
|
|
41
41
|
|
|
42
42
|
mock.expect(:call, 2, [category.id])
|
|
43
|
-
category_item.update!(name: "foo")
|
|
43
|
+
perform_enqueued_jobs { category_item.update!(name: "foo") }
|
|
44
44
|
assert_raises(MockExpectationError) { mock.verify }
|
|
45
45
|
|
|
46
46
|
mock.expect(:call, 3, [category.id])
|
|
@@ -57,7 +57,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
mock.expect(:call, 1, [category.id])
|
|
60
|
-
CategoryItem.create!(category: category)
|
|
60
|
+
perform_enqueued_jobs { CategoryItem.create!(category: category) }
|
|
61
61
|
mock.verify
|
|
62
62
|
|
|
63
63
|
mock.expect(:call, 2, [category.id])
|
|
@@ -78,13 +78,13 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
78
78
|
) { |id| mock.call(id) }
|
|
79
79
|
|
|
80
80
|
mock.expect(:call, 1, [category.id])
|
|
81
|
-
CategoryItem.create!(category: category)
|
|
81
|
+
perform_enqueued_jobs { CategoryItem.create!(category: category) }
|
|
82
82
|
mock.verify
|
|
83
83
|
|
|
84
|
-
category.update!(name: "hockey")
|
|
84
|
+
perform_enqueued_jobs { category.update!(name: "hockey") }
|
|
85
85
|
|
|
86
86
|
mock.expect(:call, 1, [category.id])
|
|
87
|
-
CategoryItem.create!(category: category)
|
|
87
|
+
perform_enqueued_jobs { CategoryItem.create!(category: category) }
|
|
88
88
|
assert_raises(MockExpectationError) { mock.verify }
|
|
89
89
|
end
|
|
90
90
|
|
|
@@ -102,7 +102,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
102
102
|
mock.verify
|
|
103
103
|
|
|
104
104
|
mock.expect(:call, 2, [category.id])
|
|
105
|
-
store.update!(name: "foo")
|
|
105
|
+
perform_enqueued_jobs { store.update!(name: "foo") }
|
|
106
106
|
mock.verify
|
|
107
107
|
|
|
108
108
|
mock.expect(:call, 3, [category.id])
|
|
@@ -142,7 +142,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
142
142
|
|
|
143
143
|
mock.expect(:call, 1, [category.id])
|
|
144
144
|
mock.expect(:call, 1, [category.id])
|
|
145
|
-
Store.create!(name: "foo", categories: [category])
|
|
145
|
+
perform_enqueued_jobs { Store.create!(name: "foo", categories: [category]) }
|
|
146
146
|
mock.verify
|
|
147
147
|
|
|
148
148
|
mock.expect(:call, 2, [category.id])
|
|
@@ -164,13 +164,13 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
164
164
|
|
|
165
165
|
mock.expect(:call, 1, [category.id])
|
|
166
166
|
mock.expect(:call, 1, [category.id])
|
|
167
|
-
Store.create!(name: "foo", categories: [category])
|
|
167
|
+
perform_enqueued_jobs { Store.create!(name: "foo", categories: [category]) }
|
|
168
168
|
mock.verify
|
|
169
169
|
|
|
170
170
|
category.update!(name: "hockey")
|
|
171
171
|
|
|
172
172
|
mock.expect(:call, 2, [category.id])
|
|
173
|
-
Store.create!(name: "bar", categories: [category])
|
|
173
|
+
perform_enqueued_jobs { Store.create!(name: "bar", categories: [category]) }
|
|
174
174
|
assert_raises(MockExpectationError) { mock.verify }
|
|
175
175
|
end
|
|
176
176
|
|
|
@@ -188,7 +188,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
188
188
|
mock.verify
|
|
189
189
|
|
|
190
190
|
mock.expect(:call, 2, [category.id])
|
|
191
|
-
product.update!(name: "foo")
|
|
191
|
+
perform_enqueued_jobs { product.update!(name: "foo") }
|
|
192
192
|
mock.verify
|
|
193
193
|
|
|
194
194
|
mock.expect(:call, 3, [category.id])
|
|
@@ -210,7 +210,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
210
210
|
mock.verify
|
|
211
211
|
|
|
212
212
|
mock.expect(:call, 2, [category.id])
|
|
213
|
-
product.update!(name: "foo")
|
|
213
|
+
perform_enqueued_jobs { product.update!(name: "foo") }
|
|
214
214
|
assert_raises(MockExpectationError) { mock.verify }
|
|
215
215
|
|
|
216
216
|
mock.expect(:call, 3, [category.id])
|
|
@@ -227,7 +227,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
227
227
|
end
|
|
228
228
|
|
|
229
229
|
mock.expect(:call, 1, [category.id])
|
|
230
|
-
Product.create!(categories: [category])
|
|
230
|
+
perform_enqueued_jobs { Product.create!(categories: [category]) }
|
|
231
231
|
mock.verify
|
|
232
232
|
|
|
233
233
|
mock.expect(:call, 2, [category.id])
|
|
@@ -248,13 +248,13 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
248
248
|
) { |id| mock.call(id) }
|
|
249
249
|
|
|
250
250
|
mock.expect(:call, 1, [category.id])
|
|
251
|
-
Product.create!(categories: [category])
|
|
251
|
+
perform_enqueued_jobs { Product.create!(categories: [category]) }
|
|
252
252
|
mock.verify
|
|
253
253
|
|
|
254
254
|
category.update!(name: "hockey")
|
|
255
255
|
|
|
256
256
|
mock.expect(:call, 2, [category.id])
|
|
257
|
-
Product.create!(categories: [category])
|
|
257
|
+
perform_enqueued_jobs { Product.create!(categories: [category]) }
|
|
258
258
|
assert_raises(MockExpectationError) { mock.verify }
|
|
259
259
|
end
|
|
260
260
|
|
|
@@ -270,13 +270,13 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
270
270
|
) { |id| mock.call(id) }
|
|
271
271
|
|
|
272
272
|
mock.expect(:call, 1, [store.id])
|
|
273
|
-
category.update!(name: "foo")
|
|
273
|
+
perform_enqueued_jobs { category.update!(name: "foo") }
|
|
274
274
|
mock.verify
|
|
275
275
|
|
|
276
276
|
mock.expect(:call, 2, [store.id])
|
|
277
277
|
assert_equal 1, Thermos.drink(key: "key", id: store.id)
|
|
278
278
|
assert_raises(MockExpectationError) { mock.verify }
|
|
279
|
-
Product.create!(categories: [category])
|
|
279
|
+
perform_enqueued_jobs { Product.create!(categories: [category]) }
|
|
280
280
|
mock.verify
|
|
281
281
|
|
|
282
282
|
mock.expect(:call, 3, [store.id])
|
|
@@ -300,7 +300,7 @@ class DependenciesTest < ActiveSupport::TestCase
|
|
|
300
300
|
|
|
301
301
|
category_mock.expect(:call, 2, [category.id])
|
|
302
302
|
product_mock.expect(:call, 2, [product.id])
|
|
303
|
-
product.update!(name: "foo")
|
|
303
|
+
perform_enqueued_jobs { product.update!(name: "foo") }
|
|
304
304
|
assert_raises(MockExpectationError) { category_mock.verify }
|
|
305
305
|
product_mock.verify
|
|
306
306
|
end
|
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
require File.expand_path("../boot", __FILE__)
|
|
2
2
|
|
|
3
|
-
require "rails
|
|
3
|
+
require "rails"
|
|
4
|
+
require "active_model/railtie"
|
|
5
|
+
require "active_job/railtie"
|
|
6
|
+
require "active_record/railtie"
|
|
7
|
+
require "action_controller/railtie"
|
|
8
|
+
require "action_mailer/railtie"
|
|
9
|
+
require "action_view/railtie"
|
|
10
|
+
# require "active_storage/engine"
|
|
11
|
+
# require "action_mailbox/engine"
|
|
12
|
+
# require "action_text/engine"
|
|
13
|
+
require "rails/test_unit/railtie"
|
|
4
14
|
|
|
5
15
|
Bundler.require(*Rails.groups)
|
|
6
16
|
require "thermos"
|
|
7
17
|
|
|
8
18
|
module Dummy
|
|
9
19
|
class Application < Rails::Application
|
|
20
|
+
# Initialize configuration defaults for originally generated Rails version.
|
|
21
|
+
config.load_defaults Rails::VERSION::STRING.to_f
|
|
22
|
+
|
|
10
23
|
# Settings in config/environments/* take precedence over those specified here.
|
|
11
24
|
# Application configuration should go into files in config/initializers
|
|
12
25
|
# -- all .rb files in that directory are automatically loaded.
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
|
|
26
|
+
|
|
27
|
+
# Don't generate system test files.
|
|
28
|
+
config.generators.system_tests = nil
|
|
29
|
+
|
|
30
|
+
# Use a real queuing backend for Active Job (and separate queues per environment).
|
|
31
|
+
config.active_job.queue_adapter = :test
|
|
19
32
|
end
|
|
20
33
|
end
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
Rails.application.configure do
|
|
2
2
|
# Settings specified here will take precedence over those in config/application.rb.
|
|
3
3
|
|
|
4
|
-
# In the development environment your application's code is reloaded
|
|
5
|
-
#
|
|
4
|
+
# In the development environment your application's code is reloaded any time
|
|
5
|
+
# it changes. This slows down response time but is perfect for development
|
|
6
6
|
# since you don't have to restart the web server when you make code changes.
|
|
7
|
-
config.
|
|
7
|
+
config.enable_reloading = true
|
|
8
8
|
|
|
9
9
|
# Do not eager load code on boot.
|
|
10
10
|
config.eager_load = false
|
|
11
11
|
|
|
12
|
-
# Show full error reports
|
|
12
|
+
# Show full error reports.
|
|
13
13
|
config.consider_all_requests_local = true
|
|
14
|
+
|
|
15
|
+
# Enable server timing.
|
|
16
|
+
config.server_timing = true
|
|
17
|
+
|
|
18
|
+
# Enable/disable caching. By default caching is disabled.
|
|
14
19
|
config.action_controller.perform_caching = false
|
|
20
|
+
config.cache_store = :memory_store
|
|
15
21
|
|
|
16
22
|
# Don't care if the mailer can't send.
|
|
17
23
|
config.action_mailer.raise_delivery_errors = false
|
|
@@ -22,20 +28,6 @@ Rails.application.configure do
|
|
|
22
28
|
# Raise an error on page load if there are pending migrations.
|
|
23
29
|
config.active_record.migration_error = :page_load
|
|
24
30
|
|
|
25
|
-
# Debug mode disables concatenation and preprocessing of assets.
|
|
26
|
-
# This option may cause significant delays in view rendering with a large
|
|
27
|
-
# number of complex assets.
|
|
28
|
-
# config.assets.debug = true
|
|
29
|
-
|
|
30
|
-
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
|
31
|
-
# yet still be able to expire them through the digest params.
|
|
32
|
-
# config.assets.digest = true
|
|
33
|
-
|
|
34
|
-
# Adds additional error checking when serving assets at runtime.
|
|
35
|
-
# Checks for improperly declared sprockets dependencies.
|
|
36
|
-
# Raises helpful error messages.
|
|
37
|
-
# config.assets.raise_runtime_errors = true
|
|
38
|
-
|
|
39
31
|
# Raises error for missing translations
|
|
40
|
-
# config.
|
|
32
|
+
# config.i18n.raise_on_missing_translations = true
|
|
41
33
|
end
|
|
@@ -2,78 +2,26 @@ Rails.application.configure do
|
|
|
2
2
|
# Settings specified here will take precedence over those in config/application.rb.
|
|
3
3
|
|
|
4
4
|
# Code is not reloaded between requests.
|
|
5
|
-
config.
|
|
5
|
+
config.enable_reloading = false
|
|
6
6
|
|
|
7
|
-
# Eager load code on boot
|
|
8
|
-
# your application in memory, allowing both threaded web servers
|
|
9
|
-
# and those relying on copy on write to perform better.
|
|
10
|
-
# Rake tasks automatically ignore this option for performance.
|
|
7
|
+
# Eager load code on boot for better performance and memory savings.
|
|
11
8
|
config.eager_load = true
|
|
12
9
|
|
|
13
|
-
# Full error reports are disabled
|
|
10
|
+
# Full error reports are disabled.
|
|
14
11
|
config.consider_all_requests_local = false
|
|
15
|
-
config.action_controller.perform_caching = true
|
|
16
|
-
|
|
17
|
-
# Enable Rack::Cache to put a simple HTTP cache in front of your application
|
|
18
|
-
# Add `rack-cache` to your Gemfile before enabling this.
|
|
19
|
-
# For large-scale production use, consider using a caching reverse proxy like
|
|
20
|
-
# NGINX, varnish or squid.
|
|
21
|
-
# config.action_dispatch.rack_cache = true
|
|
22
|
-
|
|
23
|
-
# Disable serving static files from the `/public` folder by default since
|
|
24
|
-
# Apache or NGINX already handles this.
|
|
25
|
-
config.serve_static_files = ENV["RAILS_SERVE_STATIC_FILES"].present?
|
|
26
|
-
|
|
27
|
-
# Compress JavaScripts and CSS.
|
|
28
|
-
# config.assets.js_compressor = :uglifier
|
|
29
|
-
|
|
30
|
-
# config.assets.css_compressor = :sass
|
|
31
|
-
|
|
32
|
-
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
|
33
|
-
# config.assets.compile = false
|
|
34
|
-
|
|
35
|
-
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
|
36
|
-
# yet still be able to expire them through the digest params.
|
|
37
|
-
# config.assets.digest = true
|
|
38
|
-
|
|
39
|
-
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
|
|
40
12
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
|
44
|
-
|
|
45
|
-
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
|
46
|
-
# config.force_ssl = true
|
|
47
|
-
|
|
48
|
-
# Use the lowest log level to ensure availability of diagnostic information
|
|
49
|
-
# when problems arise.
|
|
50
|
-
config.log_level = :debug
|
|
51
|
-
|
|
52
|
-
# Prepend all log lines with the following tags.
|
|
53
|
-
# config.log_tags = [ :subdomain, :uuid ]
|
|
54
|
-
|
|
55
|
-
# Use a different logger for distributed setups.
|
|
56
|
-
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
|
|
57
|
-
|
|
58
|
-
# Use a different cache store in production.
|
|
59
|
-
# config.cache_store = :mem_cache_store
|
|
60
|
-
|
|
61
|
-
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
|
|
62
|
-
# config.action_controller.asset_host = 'http://assets.example.com'
|
|
13
|
+
# Turn on fragment caching in view templates.
|
|
14
|
+
config.action_controller.perform_caching = true
|
|
63
15
|
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
# config.action_mailer.raise_delivery_errors = false
|
|
16
|
+
# Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
|
|
17
|
+
config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
|
|
67
18
|
|
|
68
19
|
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
|
69
20
|
# the I18n.default_locale when a translation cannot be found).
|
|
70
21
|
config.i18n.fallbacks = true
|
|
71
22
|
|
|
72
|
-
#
|
|
73
|
-
config.active_support.
|
|
74
|
-
|
|
75
|
-
# Use default logging formatter so that PID and timestamp are not suppressed.
|
|
76
|
-
config.log_formatter = ::Logger::Formatter.new
|
|
23
|
+
# Don't log any deprecations.
|
|
24
|
+
config.active_support.report_deprecations = false
|
|
77
25
|
|
|
78
26
|
# Do not dump schema after migrations.
|
|
79
27
|
config.active_record.dump_schema_after_migration = false
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
Rails.application.configure do
|
|
2
2
|
# Settings specified here will take precedence over those in config/application.rb.
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
# Show full error reports
|
|
4
|
+
# While tests run files are not watched, reloading is not necessary.
|
|
5
|
+
config.enable_reloading = false
|
|
6
|
+
|
|
7
|
+
# Eager loading loads your entire application. When running a single test locally,
|
|
8
|
+
# this is usually not necessary, and can slow down your test suite. However, it's
|
|
9
|
+
# recommended that you enable it in continuous integration systems to ensure eager
|
|
10
|
+
# loading is working properly before deploying your code.
|
|
11
|
+
config.eager_load = ENV["CI"].present?
|
|
12
|
+
|
|
13
|
+
# Configure public file server for tests with cache-control for performance.
|
|
14
|
+
config.public_file_server.enabled = true
|
|
15
|
+
config.public_file_server.headers = {
|
|
16
|
+
"Cache-Control" => "public, max-age=3600",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Show full error reports.
|
|
20
20
|
config.consider_all_requests_local = true
|
|
21
|
-
config.
|
|
21
|
+
config.cache_store = :memory_store
|
|
22
22
|
|
|
23
|
-
#
|
|
24
|
-
config.action_dispatch.show_exceptions =
|
|
23
|
+
# Render exception templates for rescuable exceptions and raise for other exceptions.
|
|
24
|
+
config.action_dispatch.show_exceptions = :rescuable
|
|
25
25
|
|
|
26
26
|
# Disable request forgery protection in test environment.
|
|
27
27
|
config.action_controller.allow_forgery_protection = false
|
|
@@ -31,12 +31,9 @@ Rails.application.configure do
|
|
|
31
31
|
# ActionMailer::Base.deliveries array.
|
|
32
32
|
config.action_mailer.delivery_method = :test
|
|
33
33
|
|
|
34
|
-
# Randomize the order test cases are executed.
|
|
35
|
-
config.active_support.test_order = :random
|
|
36
|
-
|
|
37
34
|
# Print deprecation notices to the stderr.
|
|
38
35
|
config.active_support.deprecation = :stderr
|
|
39
36
|
|
|
40
37
|
# Raises error for missing translations
|
|
41
|
-
# config.
|
|
38
|
+
# config.i18n.raise_on_missing_translations = true
|
|
42
39
|
end
|
data/test/dummy/db/schema.rb
CHANGED
|
@@ -10,31 +10,31 @@
|
|
|
10
10
|
#
|
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
|
12
12
|
|
|
13
|
-
ActiveRecord::Schema[
|
|
13
|
+
ActiveRecord::Schema[8.1].define(version: 2016_03_26_174530) do
|
|
14
14
|
create_table "categories", force: :cascade do |t|
|
|
15
|
+
t.datetime "created_at", precision: nil, null: false
|
|
15
16
|
t.string "name"
|
|
16
17
|
t.integer "store_id"
|
|
17
|
-
t.datetime "created_at", precision: nil, null: false
|
|
18
18
|
t.datetime "updated_at", precision: nil, null: false
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
create_table "category_items", force: :cascade do |t|
|
|
22
|
-
t.string "name"
|
|
23
22
|
t.integer "category_id"
|
|
24
|
-
t.integer "product_id"
|
|
25
23
|
t.datetime "created_at", precision: nil, null: false
|
|
24
|
+
t.string "name"
|
|
25
|
+
t.integer "product_id"
|
|
26
26
|
t.datetime "updated_at", precision: nil, null: false
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
create_table "products", force: :cascade do |t|
|
|
30
|
-
t.string "name"
|
|
31
30
|
t.datetime "created_at", precision: nil, null: false
|
|
31
|
+
t.string "name"
|
|
32
32
|
t.datetime "updated_at", precision: nil, null: false
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
create_table "stores", force: :cascade do |t|
|
|
36
|
-
t.string "name"
|
|
37
36
|
t.datetime "created_at", precision: nil, null: false
|
|
37
|
+
t.string "name"
|
|
38
38
|
t.datetime "updated_at", precision: nil, null: false
|
|
39
39
|
end
|
|
40
40
|
end
|
data/test/filter_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
2
|
|
|
3
|
-
class FilterTest <
|
|
3
|
+
class FilterTest < ActiveJob::TestCase
|
|
4
4
|
self.use_transactional_tests = true
|
|
5
5
|
teardown :clear_cache
|
|
6
6
|
|
|
@@ -16,11 +16,11 @@ class FilterTest < ActiveSupport::TestCase
|
|
|
16
16
|
) { |name| mock.call(name) }
|
|
17
17
|
|
|
18
18
|
mock.expect(:call, 1, ["basketball"])
|
|
19
|
-
category.update!(name: "basketball")
|
|
19
|
+
perform_enqueued_jobs { category.update!(name: "basketball") }
|
|
20
20
|
mock.verify
|
|
21
21
|
|
|
22
22
|
mock.expect(:call, 1, ["hockey"])
|
|
23
|
-
category.update!(name: "hockey")
|
|
23
|
+
perform_enqueued_jobs { category.update!(name: "hockey") }
|
|
24
24
|
assert_raises(MockExpectationError) { mock.verify }
|
|
25
25
|
end
|
|
26
26
|
|
data/test/test_helper.rb
CHANGED
|
@@ -6,11 +6,11 @@ ActiveRecord::Migrator.migrations_paths = [
|
|
|
6
6
|
File.expand_path("../../test/dummy/db/migrate", __FILE__),
|
|
7
7
|
]
|
|
8
8
|
require "rails/test_help"
|
|
9
|
+
require "minitest/mock"
|
|
9
10
|
|
|
10
11
|
# Filter out Minitest backtrace while allowing backtrace from other libraries
|
|
11
12
|
# to be shown.
|
|
12
13
|
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
|
13
|
-
require "minitest/mock"
|
|
14
14
|
|
|
15
15
|
# Load support files
|
|
16
16
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
@@ -29,7 +29,7 @@ elsif ActiveSupport::TestCase.respond_to?(:fixture_paths=)
|
|
|
29
29
|
end
|
|
30
30
|
ActiveSupport::TestCase.fixtures :all
|
|
31
31
|
|
|
32
|
-
ActiveJob::Base.queue_adapter = :
|
|
32
|
+
ActiveJob::Base.queue_adapter = :test
|
|
33
33
|
ActiveSupport.test_order = :random
|
|
34
34
|
|
|
35
35
|
def clear_cache
|
data/test/thermos_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
2
|
|
|
3
|
-
class ThermosTest <
|
|
3
|
+
class ThermosTest < ActiveJob::TestCase
|
|
4
4
|
self.use_transactional_tests = true
|
|
5
5
|
teardown :clear_cache
|
|
6
6
|
|
|
@@ -50,7 +50,7 @@ class ThermosTest < ActiveSupport::TestCase
|
|
|
50
50
|
mock.verify
|
|
51
51
|
|
|
52
52
|
mock.expect(:call, 2, [category.id])
|
|
53
|
-
category.update!(name: "foo")
|
|
53
|
+
perform_enqueued_jobs { category.update!(name: "foo") }
|
|
54
54
|
mock.verify
|
|
55
55
|
|
|
56
56
|
mock.expect(:call, 3, [category.id])
|
|
@@ -92,7 +92,7 @@ class ThermosTest < ActiveSupport::TestCase
|
|
|
92
92
|
mock.verify
|
|
93
93
|
|
|
94
94
|
mock.expect(:call, 1, [category.id])
|
|
95
|
-
category.update!(name: "foo")
|
|
95
|
+
perform_enqueued_jobs { category.update!(name: "foo") }
|
|
96
96
|
mock.verify
|
|
97
97
|
|
|
98
98
|
mock.expect(:call, 3, [other_category.id])
|
|
@@ -123,7 +123,7 @@ class ThermosTest < ActiveSupport::TestCase
|
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
mock.expect(:call, 1, ["foo"])
|
|
126
|
-
Category.create!(name: "foo")
|
|
126
|
+
perform_enqueued_jobs { Category.create!(name: "foo") }
|
|
127
127
|
mock.verify
|
|
128
128
|
|
|
129
129
|
mock.expect(:call, 2, ["foo"])
|
|
@@ -144,7 +144,7 @@ class ThermosTest < ActiveSupport::TestCase
|
|
|
144
144
|
mock.verify
|
|
145
145
|
|
|
146
146
|
mock.expect(:call, 2, ["foo"])
|
|
147
|
-
category.update!(name: "foo")
|
|
147
|
+
perform_enqueued_jobs { category.update!(name: "foo") }
|
|
148
148
|
mock.verify
|
|
149
149
|
|
|
150
150
|
mock.expect(:call, 3, [category.name])
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: thermos
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Thal
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-12-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -16,30 +16,36 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '7.1'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9'
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
27
|
- - ">="
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
29
|
+
version: '7.1'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9'
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
34
|
+
name: minitest
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
30
36
|
requirements:
|
|
31
|
-
- - "
|
|
37
|
+
- - "~>"
|
|
32
38
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
39
|
+
version: '5.0'
|
|
34
40
|
type: :development
|
|
35
41
|
prerelease: false
|
|
36
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
43
|
requirements:
|
|
38
|
-
- - "
|
|
44
|
+
- - "~>"
|
|
39
45
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
46
|
+
version: '5.0'
|
|
41
47
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
48
|
+
name: rake
|
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
|
44
50
|
requirements:
|
|
45
51
|
- - ">="
|
|
@@ -53,7 +59,7 @@ dependencies:
|
|
|
53
59
|
- !ruby/object:Gem::Version
|
|
54
60
|
version: '0'
|
|
55
61
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
62
|
+
name: sqlite3
|
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
|
58
64
|
requirements:
|
|
59
65
|
- - ">="
|
|
@@ -67,22 +73,26 @@ dependencies:
|
|
|
67
73
|
- !ruby/object:Gem::Version
|
|
68
74
|
version: '0'
|
|
69
75
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
76
|
+
name: prettier
|
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
|
72
78
|
requirements:
|
|
73
|
-
- - "
|
|
79
|
+
- - ">="
|
|
74
80
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
81
|
+
version: '0'
|
|
76
82
|
type: :development
|
|
77
83
|
prerelease: false
|
|
78
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
85
|
requirements:
|
|
80
|
-
- - "
|
|
86
|
+
- - ">="
|
|
81
87
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
88
|
+
version: '0'
|
|
83
89
|
description: |
|
|
84
|
-
Thermos is a library
|
|
85
|
-
in the background
|
|
90
|
+
Thermos is a Rails caching library that keeps your cache always warm by
|
|
91
|
+
automatically rebuilding it in the background when ActiveRecord models change.
|
|
92
|
+
No more stale data from TTL expiration, no more slow cold cache hits, and no
|
|
93
|
+
need to 'touch' associated models. Works with any ActiveJob backend (Sidekiq,
|
|
94
|
+
Solid Queue, etc.) and any cache store (Redis, Memcached, Solid Cache, etc.).
|
|
95
|
+
Perfect for API responses, JSON serialization, and view caching.
|
|
86
96
|
email:
|
|
87
97
|
- athal7@me.com
|
|
88
98
|
executables: []
|
|
@@ -90,6 +100,7 @@ extensions: []
|
|
|
90
100
|
extra_rdoc_files: []
|
|
91
101
|
files:
|
|
92
102
|
- MIT-LICENSE
|
|
103
|
+
- README.md
|
|
93
104
|
- Rakefile
|
|
94
105
|
- lib/thermos.rb
|
|
95
106
|
- lib/thermos/beverage.rb
|
|
@@ -130,7 +141,6 @@ files:
|
|
|
130
141
|
- test/dummy/config/initializers/filter_parameter_logging.rb
|
|
131
142
|
- test/dummy/config/initializers/inflections.rb
|
|
132
143
|
- test/dummy/config/initializers/mime_types.rb
|
|
133
|
-
- test/dummy/config/initializers/session_store.rb
|
|
134
144
|
- test/dummy/config/initializers/wrap_parameters.rb
|
|
135
145
|
- test/dummy/config/locales/en.yml
|
|
136
146
|
- test/dummy/config/routes.rb
|
|
@@ -155,26 +165,31 @@ files:
|
|
|
155
165
|
homepage: https://github.com/athal7/thermos
|
|
156
166
|
licenses:
|
|
157
167
|
- MIT
|
|
158
|
-
metadata:
|
|
159
|
-
|
|
168
|
+
metadata:
|
|
169
|
+
homepage_uri: https://github.com/athal7/thermos
|
|
170
|
+
source_code_uri: https://github.com/athal7/thermos
|
|
171
|
+
changelog_uri: https://github.com/athal7/thermos/releases
|
|
172
|
+
rubygems_mfa_required: 'true'
|
|
173
|
+
post_install_message:
|
|
160
174
|
rdoc_options: []
|
|
161
175
|
require_paths:
|
|
162
176
|
- lib
|
|
163
177
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
178
|
requirements:
|
|
165
|
-
- - "
|
|
179
|
+
- - ">="
|
|
166
180
|
- !ruby/object:Gem::Version
|
|
167
|
-
version: '3.
|
|
181
|
+
version: '3.2'
|
|
168
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
183
|
requirements:
|
|
170
184
|
- - ">="
|
|
171
185
|
- !ruby/object:Gem::Version
|
|
172
186
|
version: '0'
|
|
173
187
|
requirements: []
|
|
174
|
-
rubygems_version: 3.5.
|
|
175
|
-
signing_key:
|
|
188
|
+
rubygems_version: 3.5.22
|
|
189
|
+
signing_key:
|
|
176
190
|
specification_version: 4
|
|
177
|
-
summary: Always-warm, auto-rebuilding
|
|
191
|
+
summary: Always-warm, auto-rebuilding Rails cache that updates in the background when
|
|
192
|
+
models change.
|
|
178
193
|
test_files:
|
|
179
194
|
- test/dependencies_test.rb
|
|
180
195
|
- test/dummy/README.rdoc
|
|
@@ -206,7 +221,6 @@ test_files:
|
|
|
206
221
|
- test/dummy/config/initializers/filter_parameter_logging.rb
|
|
207
222
|
- test/dummy/config/initializers/inflections.rb
|
|
208
223
|
- test/dummy/config/initializers/mime_types.rb
|
|
209
|
-
- test/dummy/config/initializers/session_store.rb
|
|
210
224
|
- test/dummy/config/initializers/wrap_parameters.rb
|
|
211
225
|
- test/dummy/config/locales/en.yml
|
|
212
226
|
- test/dummy/config/routes.rb
|