thermos 0.5.0 → 0.6.0
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/Rakefile +4 -0
- data/lib/thermos/beverage.rb +42 -24
- data/lib/thermos/notifier.rb +1 -3
- data/lib/thermos/refill_job.rb +9 -5
- data/lib/thermos/version.rb +1 -1
- data/lib/thermos.rb +25 -7
- data/test/dependencies_test.rb +307 -0
- data/test/dummy/app/models/category.rb +8 -6
- data/test/dummy/config/application.rb +1 -4
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/environments/production.rb +2 -1
- data/test/dummy/config/environments/test.rb +2 -2
- data/test/dummy/config/routes.rb +0 -9
- data/test/dummy/db/schema.rb +19 -21
- data/test/filter_test.rb +52 -0
- data/test/fixtures/stores.yml +2 -0
- data/test/queue_test.rb +36 -0
- data/test/test_helper.rb +16 -6
- data/test/thermos_test.rb +47 -297
- metadata +54 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3979389850e8fc2f1d7ffede3e023a8e9f81e5d1239f403fa79c1df49dd8f3e
|
4
|
+
data.tar.gz: 89806ca4b6ae5a81d121ae42adb784585852dd1af385d2f8067631b9cdd330a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ceaaf4c53a3b06e012d66f1f60476c0278d973543a3d8dfb050e9637338dbe789cbb2b206d87d3e5b0f0cf60a130d85bc2119ec059f21bfffce7e1eef16eeb7
|
7
|
+
data.tar.gz: 1f5fc62f26e008e76059775cf273fcf05ea8b1be930acf5b25af3d3a0b36a11f9beae3f7a9b9083cb5869efb45105bb98e3cb1d22b443f61910934fed26c9315
|
data/Rakefile
CHANGED
data/lib/thermos/beverage.rb
CHANGED
@@ -2,27 +2,44 @@
|
|
2
2
|
|
3
3
|
module Thermos
|
4
4
|
class Beverage
|
5
|
-
attr_reader :key, :model, :deps, :action, :lookup_key, :filter
|
5
|
+
attr_reader :key, :model, :deps, :action, :lookup_key, :filter, :queue
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(
|
8
|
+
key:,
|
9
|
+
model:,
|
10
|
+
deps:,
|
11
|
+
action:,
|
12
|
+
lookup_key: nil,
|
13
|
+
filter: nil,
|
14
|
+
queue: nil
|
15
|
+
)
|
8
16
|
@key = key
|
9
17
|
@model = model
|
10
18
|
@lookup_key = lookup_key || :id
|
11
19
|
@filter = filter || nil
|
12
20
|
@deps = generate_deps(model, deps)
|
13
21
|
@action = action
|
22
|
+
@queue = queue || ActiveJob::Base.default_queue_name
|
14
23
|
|
15
24
|
set_observers
|
16
25
|
end
|
17
26
|
|
18
27
|
def lookup_keys_for_dep_model(dep_model)
|
19
|
-
@deps
|
20
|
-
dep.klass == dep_model.class
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
@deps
|
29
|
+
.select { |dep| dep.klass == dep_model.class }
|
30
|
+
.flat_map do |dep|
|
31
|
+
lookup_keys = []
|
32
|
+
|
33
|
+
@model
|
34
|
+
.joins(dep.path)
|
35
|
+
.where(dep.table => { id: dep_model.id })
|
36
|
+
.find_each do |model|
|
37
|
+
lookup_keys << model.send(@lookup_key) if should_fill?(model)
|
38
|
+
end
|
39
|
+
|
40
|
+
lookup_keys
|
41
|
+
end
|
42
|
+
.uniq
|
26
43
|
end
|
27
44
|
|
28
45
|
def should_fill?(model)
|
@@ -43,25 +60,26 @@ module Thermos
|
|
43
60
|
def generate_deps(model, deps, root = nil, path = nil)
|
44
61
|
deps.reduce([]) do |acc, dep|
|
45
62
|
if dep.is_a? Symbol
|
46
|
-
acc <<
|
47
|
-
|
48
|
-
|
49
|
-
|
63
|
+
acc <<
|
64
|
+
Dependency.new(
|
65
|
+
model: root || model,
|
66
|
+
ref: model.reflect_on_association(dep),
|
67
|
+
path: path || dep,
|
68
|
+
)
|
50
69
|
elsif dep.is_a? Array
|
51
|
-
dep.each do |d|
|
52
|
-
acc <<
|
53
|
-
|
54
|
-
|
55
|
-
|
70
|
+
dep.each do |d|
|
71
|
+
acc <<
|
72
|
+
Dependency.new(
|
73
|
+
model: root || model,
|
74
|
+
ref: model.reflect_on_association(d),
|
75
|
+
path: path || d,
|
76
|
+
)
|
56
77
|
end
|
57
78
|
elsif dep.is_a? Hash
|
58
|
-
dep.each do |k,v|
|
79
|
+
dep.each do |k, v|
|
59
80
|
ref = model.reflect_on_association(k)
|
60
|
-
acc <<
|
61
|
-
model: root || model,
|
62
|
-
ref: ref,
|
63
|
-
path: path || k
|
64
|
-
)
|
81
|
+
acc <<
|
82
|
+
Dependency.new(model: root || model, ref: ref, path: path || k)
|
65
83
|
acc.concat(generate_deps(ref.class_name.constantize, v, model, dep))
|
66
84
|
end
|
67
85
|
end
|
data/lib/thermos/notifier.rb
CHANGED
data/lib/thermos/refill_job.rb
CHANGED
@@ -10,18 +10,22 @@ module Thermos
|
|
10
10
|
def refill_primary_caches(model)
|
11
11
|
BeverageStorage.instance.beverages.each do |beverage|
|
12
12
|
if beverage.model == model.class && beverage.should_fill?(model)
|
13
|
-
Thermos::RebuildCacheJob
|
13
|
+
Thermos::RebuildCacheJob
|
14
|
+
.set(queue: beverage.queue)
|
15
|
+
.perform_later(beverage.key, model.send(beverage.lookup_key))
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
def refill_dependency_caches(model)
|
19
21
|
BeverageStorage.instance.beverages.each do |beverage|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
beverage
|
23
|
+
.lookup_keys_for_dep_model(model)
|
24
|
+
.each do |lookup_key|
|
25
|
+
Thermos::RebuildCacheJob
|
26
|
+
.set(queue: beverage.queue)
|
27
|
+
.perform_later(beverage.key, lookup_key)
|
23
28
|
end
|
24
|
-
end
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
data/lib/thermos/version.rb
CHANGED
data/lib/thermos.rb
CHANGED
@@ -8,20 +8,38 @@ require 'thermos/refill_job'
|
|
8
8
|
require 'thermos/rebuild_cache_job'
|
9
9
|
|
10
10
|
module Thermos
|
11
|
-
def self.keep_warm(key:, model:, id:, deps: [], lookup_key: nil, filter: nil, &block)
|
12
|
-
fill(
|
11
|
+
def self.keep_warm(key:, model:, id:, deps: [], lookup_key: nil, filter: nil, queue: nil, &block)
|
12
|
+
fill(
|
13
|
+
key: key,
|
14
|
+
model: model,
|
15
|
+
deps: deps,
|
16
|
+
lookup_key: lookup_key,
|
17
|
+
filter: filter,
|
18
|
+
queue: queue,
|
19
|
+
&block
|
20
|
+
)
|
13
21
|
drink(key: key, id: id)
|
14
22
|
end
|
15
23
|
|
16
|
-
def self.fill(key:, model:, deps: [], lookup_key: nil, filter: nil, &block)
|
24
|
+
def self.fill(key:, model:, deps: [], lookup_key: nil, filter: nil, queue: nil, &block)
|
17
25
|
BeverageStorage.instance.add_beverage(
|
18
|
-
Beverage.new(
|
26
|
+
Beverage.new(
|
27
|
+
key: key,
|
28
|
+
model: model,
|
29
|
+
deps: deps,
|
30
|
+
action: block,
|
31
|
+
lookup_key: lookup_key,
|
32
|
+
filter: filter,
|
33
|
+
queue: queue
|
34
|
+
)
|
19
35
|
)
|
20
36
|
end
|
21
37
|
|
22
38
|
def self.drink(key:, id:)
|
23
|
-
Rails
|
24
|
-
|
25
|
-
|
39
|
+
Rails
|
40
|
+
.cache
|
41
|
+
.fetch([key, id]) do
|
42
|
+
BeverageStorage.instance.get_beverage(key).action.call(id)
|
43
|
+
end
|
26
44
|
end
|
27
45
|
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DependenciesTest < ActiveSupport::TestCase
|
4
|
+
self.use_transactional_tests = true
|
5
|
+
teardown :clear_cache
|
6
|
+
|
7
|
+
test 'rebuilds the cache on has_many model change' do
|
8
|
+
mock = Minitest::Mock.new
|
9
|
+
category = categories(:baseball)
|
10
|
+
category_item = category_items(:baseball_glove)
|
11
|
+
|
12
|
+
Thermos.fill(key: 'key', model: Category, deps: [:category_items]) do |id|
|
13
|
+
mock.call(id)
|
14
|
+
end
|
15
|
+
|
16
|
+
mock.expect(:call, 1, [category.id])
|
17
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
18
|
+
mock.verify
|
19
|
+
|
20
|
+
mock.expect(:call, 2, [category.id])
|
21
|
+
category_item.update!(name: 'foo')
|
22
|
+
mock.verify
|
23
|
+
|
24
|
+
mock.expect(:call, 3, [category.id])
|
25
|
+
assert_equal 2, Thermos.drink(key: 'key', id: category.id)
|
26
|
+
assert_raises(MockExpectationError) { mock.verify }
|
27
|
+
end
|
28
|
+
|
29
|
+
test 'does not rebuild the cache for an unrelated has_many model change' do
|
30
|
+
mock = Minitest::Mock.new
|
31
|
+
category = categories(:baseball)
|
32
|
+
category_item = CategoryItem.create(category: nil)
|
33
|
+
|
34
|
+
Thermos.fill(key: 'key', model: Category, deps: [:category_items]) do |id|
|
35
|
+
mock.call(id)
|
36
|
+
end
|
37
|
+
|
38
|
+
mock.expect(:call, 1, [category.id])
|
39
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
40
|
+
mock.verify
|
41
|
+
|
42
|
+
mock.expect(:call, 2, [category.id])
|
43
|
+
category_item.update!(name: 'foo')
|
44
|
+
assert_raises(MockExpectationError) { mock.verify }
|
45
|
+
|
46
|
+
mock.expect(:call, 3, [category.id])
|
47
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
48
|
+
assert_raises(MockExpectationError) { mock.verify }
|
49
|
+
end
|
50
|
+
|
51
|
+
test 're-builds the cache for new has_many records' do
|
52
|
+
mock = Minitest::Mock.new
|
53
|
+
category = categories(:baseball)
|
54
|
+
|
55
|
+
Thermos.fill(key: 'key', model: Category, deps: [:category_items]) do |id|
|
56
|
+
mock.call(id)
|
57
|
+
end
|
58
|
+
|
59
|
+
mock.expect(:call, 1, [category.id])
|
60
|
+
CategoryItem.create!(category: category)
|
61
|
+
mock.verify
|
62
|
+
|
63
|
+
mock.expect(:call, 2, [category.id])
|
64
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
65
|
+
assert_raises(MockExpectationError) { mock.verify }
|
66
|
+
end
|
67
|
+
|
68
|
+
test 're-builds the cache for has_many record changes when filter condition is met' do
|
69
|
+
mock = Minitest::Mock.new
|
70
|
+
category = categories(:baseball)
|
71
|
+
filter = ->(model) { model.ball? }
|
72
|
+
|
73
|
+
Thermos.fill(
|
74
|
+
key: 'key',
|
75
|
+
model: Category,
|
76
|
+
deps: [:category_items],
|
77
|
+
filter: filter,
|
78
|
+
) { |id| mock.call(id) }
|
79
|
+
|
80
|
+
mock.expect(:call, 1, [category.id])
|
81
|
+
CategoryItem.create!(category: category)
|
82
|
+
mock.verify
|
83
|
+
|
84
|
+
category.update!(name: 'hockey')
|
85
|
+
|
86
|
+
mock.expect(:call, 1, [category.id])
|
87
|
+
CategoryItem.create!(category: category)
|
88
|
+
assert_raises(MockExpectationError) { mock.verify }
|
89
|
+
end
|
90
|
+
|
91
|
+
test 'rebuilds the cache on belongs_to model change' do
|
92
|
+
mock = Minitest::Mock.new
|
93
|
+
category = categories(:baseball)
|
94
|
+
store = stores(:sports)
|
95
|
+
|
96
|
+
Thermos.fill(key: 'key', model: Category, deps: [:store]) do |id|
|
97
|
+
mock.call(id)
|
98
|
+
end
|
99
|
+
|
100
|
+
mock.expect(:call, 1, [category.id])
|
101
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
102
|
+
mock.verify
|
103
|
+
|
104
|
+
mock.expect(:call, 2, [category.id])
|
105
|
+
store.update!(name: 'foo')
|
106
|
+
mock.verify
|
107
|
+
|
108
|
+
mock.expect(:call, 3, [category.id])
|
109
|
+
assert_equal 2, Thermos.drink(key: 'key', id: category.id)
|
110
|
+
assert_raises(MockExpectationError) { mock.verify }
|
111
|
+
end
|
112
|
+
|
113
|
+
test 'does not rebuild the cache for an unrelated belongs_to model change' do
|
114
|
+
mock = Minitest::Mock.new
|
115
|
+
category = categories(:baseball)
|
116
|
+
store = Store.create!
|
117
|
+
|
118
|
+
Thermos.fill(key: 'key', model: Category, deps: [:store]) do |id|
|
119
|
+
mock.call(id)
|
120
|
+
end
|
121
|
+
|
122
|
+
mock.expect(:call, 1, [category.id])
|
123
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
124
|
+
mock.verify
|
125
|
+
|
126
|
+
mock.expect(:call, 2, [category.id])
|
127
|
+
store.update!(name: 'foo')
|
128
|
+
assert_raises(MockExpectationError) { mock.verify }
|
129
|
+
|
130
|
+
mock.expect(:call, 3, [category.id])
|
131
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
132
|
+
assert_raises(MockExpectationError) { mock.verify }
|
133
|
+
end
|
134
|
+
|
135
|
+
test 're-builds the cache for new belongs_to records' do
|
136
|
+
mock = Minitest::Mock.new
|
137
|
+
category = categories(:baseball)
|
138
|
+
|
139
|
+
Thermos.fill(key: 'key', model: Category, deps: [:store]) do |id|
|
140
|
+
mock.call(id)
|
141
|
+
end
|
142
|
+
|
143
|
+
mock.expect(:call, 1, [category.id])
|
144
|
+
mock.expect(:call, 1, [category.id])
|
145
|
+
Store.create!(name: 'foo', categories: [category])
|
146
|
+
mock.verify
|
147
|
+
|
148
|
+
mock.expect(:call, 2, [category.id])
|
149
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
150
|
+
assert_raises(MockExpectationError) { mock.verify }
|
151
|
+
end
|
152
|
+
|
153
|
+
test 're-builds the cache for belongs_to record changes when filter condition is met' do
|
154
|
+
mock = Minitest::Mock.new
|
155
|
+
category = categories(:baseball)
|
156
|
+
filter = ->(model) { model.ball? }
|
157
|
+
|
158
|
+
Thermos.fill(
|
159
|
+
key: 'key',
|
160
|
+
model: Category,
|
161
|
+
deps: [:store],
|
162
|
+
filter: filter,
|
163
|
+
) { |id| mock.call(id) }
|
164
|
+
|
165
|
+
mock.expect(:call, 1, [category.id])
|
166
|
+
mock.expect(:call, 1, [category.id])
|
167
|
+
Store.create!(name: 'foo', categories: [category])
|
168
|
+
mock.verify
|
169
|
+
|
170
|
+
category.update!(name: 'hockey')
|
171
|
+
|
172
|
+
mock.expect(:call, 2, [category.id])
|
173
|
+
Store.create!(name: 'bar', categories: [category])
|
174
|
+
assert_raises(MockExpectationError) { mock.verify }
|
175
|
+
end
|
176
|
+
|
177
|
+
test 'rebuilds the cache on has_many through model change' do
|
178
|
+
mock = Minitest::Mock.new
|
179
|
+
category = categories(:baseball)
|
180
|
+
product = products(:glove)
|
181
|
+
|
182
|
+
Thermos.fill(key: 'key', model: Category, deps: [:products]) do |id|
|
183
|
+
mock.call(id)
|
184
|
+
end
|
185
|
+
|
186
|
+
mock.expect(:call, 1, [category.id])
|
187
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
188
|
+
mock.verify
|
189
|
+
|
190
|
+
mock.expect(:call, 2, [category.id])
|
191
|
+
product.update!(name: 'foo')
|
192
|
+
mock.verify
|
193
|
+
|
194
|
+
mock.expect(:call, 3, [category.id])
|
195
|
+
assert_equal 2, Thermos.drink(key: 'key', id: category.id)
|
196
|
+
assert_raises(MockExpectationError) { mock.verify }
|
197
|
+
end
|
198
|
+
|
199
|
+
test 'does not rebuild the cache for an unrelated has_many through model change' do
|
200
|
+
mock = Minitest::Mock.new
|
201
|
+
category = categories(:baseball)
|
202
|
+
product = Product.create!
|
203
|
+
|
204
|
+
Thermos.fill(key: 'key', model: Category, deps: [:products]) do |id|
|
205
|
+
mock.call(id)
|
206
|
+
end
|
207
|
+
|
208
|
+
mock.expect(:call, 1, [category.id])
|
209
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
210
|
+
mock.verify
|
211
|
+
|
212
|
+
mock.expect(:call, 2, [category.id])
|
213
|
+
product.update!(name: 'foo')
|
214
|
+
assert_raises(MockExpectationError) { mock.verify }
|
215
|
+
|
216
|
+
mock.expect(:call, 3, [category.id])
|
217
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
218
|
+
assert_raises(MockExpectationError) { mock.verify }
|
219
|
+
end
|
220
|
+
|
221
|
+
test 're-builds the cache for new has_many through records' do
|
222
|
+
mock = Minitest::Mock.new
|
223
|
+
category = categories(:baseball)
|
224
|
+
|
225
|
+
Thermos.fill(key: 'key', model: Category, deps: [:products]) do |id|
|
226
|
+
mock.call(id)
|
227
|
+
end
|
228
|
+
|
229
|
+
mock.expect(:call, 1, [category.id])
|
230
|
+
Product.create!(categories: [category])
|
231
|
+
mock.verify
|
232
|
+
|
233
|
+
mock.expect(:call, 2, [category.id])
|
234
|
+
assert_equal 1, Thermos.drink(key: 'key', id: category.id)
|
235
|
+
assert_raises(MockExpectationError) { mock.verify }
|
236
|
+
end
|
237
|
+
|
238
|
+
test 're-builds the cache for has_many through record changes when filter condition is met' do
|
239
|
+
mock = Minitest::Mock.new
|
240
|
+
category = categories(:baseball)
|
241
|
+
filter = ->(model) { model.ball? }
|
242
|
+
|
243
|
+
Thermos.fill(
|
244
|
+
key: 'key',
|
245
|
+
model: Category,
|
246
|
+
deps: [:products],
|
247
|
+
filter: filter,
|
248
|
+
) { |id| mock.call(id) }
|
249
|
+
|
250
|
+
mock.expect(:call, 1, [category.id])
|
251
|
+
Product.create!(categories: [category])
|
252
|
+
mock.verify
|
253
|
+
|
254
|
+
category.update!(name: 'hockey')
|
255
|
+
|
256
|
+
mock.expect(:call, 2, [category.id])
|
257
|
+
Product.create!(categories: [category])
|
258
|
+
assert_raises(MockExpectationError) { mock.verify }
|
259
|
+
end
|
260
|
+
|
261
|
+
test 'handles indirect associations' do
|
262
|
+
mock = Minitest::Mock.new
|
263
|
+
category = categories(:baseball)
|
264
|
+
store = category.store
|
265
|
+
|
266
|
+
Thermos.fill(
|
267
|
+
key: 'key',
|
268
|
+
model: Store,
|
269
|
+
deps: [categories: [:products]],
|
270
|
+
) { |id| mock.call(id) }
|
271
|
+
|
272
|
+
mock.expect(:call, 1, [store.id])
|
273
|
+
category.update!(name: 'foo')
|
274
|
+
mock.verify
|
275
|
+
|
276
|
+
mock.expect(:call, 2, [store.id])
|
277
|
+
assert_equal 1, Thermos.drink(key: 'key', id: store.id)
|
278
|
+
assert_raises(MockExpectationError) { mock.verify }
|
279
|
+
Product.create!(categories: [category])
|
280
|
+
mock.verify
|
281
|
+
|
282
|
+
mock.expect(:call, 3, [store.id])
|
283
|
+
assert_equal 2, Thermos.drink(key: 'key', id: store.id)
|
284
|
+
assert_raises(MockExpectationError) { mock.verify }
|
285
|
+
end
|
286
|
+
|
287
|
+
test 'only rebuilds cache for stated dependencies, even if another cache has an associated model of the primary' do
|
288
|
+
category_mock = Minitest::Mock.new
|
289
|
+
product_mock = Minitest::Mock.new
|
290
|
+
category = categories(:baseball)
|
291
|
+
product = products(:glove)
|
292
|
+
|
293
|
+
Thermos.fill(key: 'category_key', model: Category) do |id|
|
294
|
+
category_mock.call(id)
|
295
|
+
end
|
296
|
+
|
297
|
+
Thermos.fill(key: 'product_key', model: Product) do |id|
|
298
|
+
product_mock.call(id)
|
299
|
+
end
|
300
|
+
|
301
|
+
category_mock.expect(:call, 2, [category.id])
|
302
|
+
product_mock.expect(:call, 2, [product.id])
|
303
|
+
product.update!(name: 'foo')
|
304
|
+
assert_raises(MockExpectationError) { category_mock.verify }
|
305
|
+
product_mock.verify
|
306
|
+
end
|
307
|
+
end
|
@@ -3,16 +3,18 @@ class Category < ActiveRecord::Base
|
|
3
3
|
has_many :products, through: :category_items
|
4
4
|
belongs_to :store
|
5
5
|
|
6
|
+
def ball?
|
7
|
+
name.match('ball')
|
8
|
+
end
|
9
|
+
|
6
10
|
def as_json(*args)
|
7
11
|
{
|
8
12
|
name: name,
|
9
13
|
store_name: store.name,
|
10
|
-
category_items:
|
11
|
-
|
12
|
-
name: item.name,
|
13
|
-
|
14
|
-
}
|
15
|
-
end
|
14
|
+
category_items:
|
15
|
+
category_items.map do |item|
|
16
|
+
{ name: item.name, product_name: item.product.name }
|
17
|
+
end,
|
16
18
|
}
|
17
19
|
end
|
18
20
|
end
|
@@ -3,21 +3,18 @@ require File.expand_path('../boot', __FILE__)
|
|
3
3
|
require 'rails/all'
|
4
4
|
|
5
5
|
Bundler.require(*Rails.groups)
|
6
|
-
require
|
6
|
+
require 'thermos'
|
7
7
|
|
8
8
|
module Dummy
|
9
9
|
class Application < Rails::Application
|
10
10
|
# Settings in config/environments/* take precedence over those specified here.
|
11
11
|
# Application configuration should go into files in config/initializers
|
12
12
|
# -- all .rb files in that directory are automatically loaded.
|
13
|
-
|
14
13
|
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
15
14
|
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
16
15
|
# config.time_zone = 'Central Time (US & Canada)'
|
17
|
-
|
18
16
|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
19
17
|
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
20
18
|
# config.i18n.default_locale = :de
|
21
19
|
end
|
22
20
|
end
|
23
|
-
|
@@ -10,7 +10,7 @@ Rails.application.configure do
|
|
10
10
|
config.eager_load = false
|
11
11
|
|
12
12
|
# Show full error reports and disable caching.
|
13
|
-
config.consider_all_requests_local
|
13
|
+
config.consider_all_requests_local = true
|
14
14
|
config.action_controller.perform_caching = false
|
15
15
|
|
16
16
|
# Don't care if the mailer can't send.
|
@@ -11,7 +11,7 @@ Rails.application.configure do
|
|
11
11
|
config.eager_load = true
|
12
12
|
|
13
13
|
# Full error reports are disabled and caching is turned on.
|
14
|
-
config.consider_all_requests_local
|
14
|
+
config.consider_all_requests_local = false
|
15
15
|
config.action_controller.perform_caching = true
|
16
16
|
|
17
17
|
# Enable Rack::Cache to put a simple HTTP cache in front of your application
|
@@ -26,6 +26,7 @@ Rails.application.configure do
|
|
26
26
|
|
27
27
|
# Compress JavaScripts and CSS.
|
28
28
|
config.assets.js_compressor = :uglifier
|
29
|
+
|
29
30
|
# config.assets.css_compressor = :sass
|
30
31
|
|
31
32
|
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
@@ -13,11 +13,11 @@ Rails.application.configure do
|
|
13
13
|
config.eager_load = false
|
14
14
|
|
15
15
|
# Configure static file server for tests with Cache-Control for performance.
|
16
|
-
config.serve_static_files
|
16
|
+
config.serve_static_files = true
|
17
17
|
config.static_cache_control = 'public, max-age=3600'
|
18
18
|
|
19
19
|
# Show full error reports and disable caching.
|
20
|
-
config.consider_all_requests_local
|
20
|
+
config.consider_all_requests_local = true
|
21
21
|
config.action_controller.perform_caching = false
|
22
22
|
|
23
23
|
# Raise exceptions instead of rendering exception templates.
|
data/test/dummy/config/routes.rb
CHANGED
@@ -1,19 +1,14 @@
|
|
1
1
|
Rails.application.routes.draw do
|
2
2
|
# The priority is based upon order of creation: first created -> highest priority.
|
3
3
|
# See how all your routes lay out with "rake routes".
|
4
|
-
|
5
4
|
# You can have the root of your site routed with "root"
|
6
5
|
# root 'welcome#index'
|
7
|
-
|
8
6
|
# Example of regular route:
|
9
7
|
# get 'products/:id' => 'catalog#view'
|
10
|
-
|
11
8
|
# Example of named route that can be invoked with purchase_url(id: product.id)
|
12
9
|
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
|
13
|
-
|
14
10
|
# Example resource route (maps HTTP verbs to controller actions automatically):
|
15
11
|
# resources :products
|
16
|
-
|
17
12
|
# Example resource route with options:
|
18
13
|
# resources :products do
|
19
14
|
# member do
|
@@ -25,13 +20,11 @@ Rails.application.routes.draw do
|
|
25
20
|
# get 'sold'
|
26
21
|
# end
|
27
22
|
# end
|
28
|
-
|
29
23
|
# Example resource route with sub-resources:
|
30
24
|
# resources :products do
|
31
25
|
# resources :comments, :sales
|
32
26
|
# resource :seller
|
33
27
|
# end
|
34
|
-
|
35
28
|
# Example resource route with more complex sub-resources:
|
36
29
|
# resources :products do
|
37
30
|
# resources :comments
|
@@ -39,14 +32,12 @@ Rails.application.routes.draw do
|
|
39
32
|
# get 'recent', on: :collection
|
40
33
|
# end
|
41
34
|
# end
|
42
|
-
|
43
35
|
# Example resource route with concerns:
|
44
36
|
# concern :toggleable do
|
45
37
|
# post 'toggle'
|
46
38
|
# end
|
47
39
|
# resources :posts, concerns: :toggleable
|
48
40
|
# resources :photos, concerns: :toggleable
|
49
|
-
|
50
41
|
# Example resource route within a namespace:
|
51
42
|
# namespace :admin do
|
52
43
|
# # Directs /admin/products/* to Admin::ProductsController
|