builder-rails_cache 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c4aa749a4640d7ca3fe3729890999c3c51fe0bd1b273cde488367410c9496acf
4
+ data.tar.gz: a117fcaef9eaa8b354b3d047585d43af8e0261c4bddf66c903f735cfa2ec9f44
5
+ SHA512:
6
+ metadata.gz: ba317a626c14dda2d79925cee3757ce47ead9ec88a5ecb1bfff034c65e72be0619f232d552d79f1d819cf0ce1900c716e957faaa0ef3141c78273e5b53b1fd8d
7
+ data.tar.gz: ec9cca1b5820d6e03ab90d8d0903f44494c50c193c79d95d6aebf66cf79d34e284d9ee56dd16452f8d57ff23cb1eb8950ef695ab577d1723d639391be1ba838e
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-11-21
4
+
5
+ - Initial release
data/README.md ADDED
@@ -0,0 +1,321 @@
1
+ # Builder::RailsCache
2
+
3
+ Provides a convenient `with_cache do ... end` wrapper around caching Rails responses, and shared_examples for use in your controller tests.
4
+
5
+ ```ruby
6
+ def index
7
+ # Cache the response across all users
8
+ json = with_cache do
9
+ # this code will only be called
10
+ # if the response is already cached,
11
+ # and the cache entry has not expired
12
+ @records = MyModelClass.where(....)
13
+ # The return value of the block will be
14
+ # what gets stored in the cache, so it's
15
+ # simplest to just return the generated JSON
16
+ @records.to_json
17
+ end
18
+ # render whatever we got back from the cache if it was a hit,
19
+ # or whatever the block generated if it was a cache miss
20
+ render json: json, status: :ok
21
+ end
22
+ ```
23
+
24
+ ## Installation
25
+
26
+ 1. Add the gem to your Gemfile:
27
+
28
+ ```ruby
29
+ gem 'builder-rails_cache'
30
+ ```
31
+
32
+ 2. Install the gem
33
+
34
+ ```bash
35
+ > bundle
36
+ ```
37
+
38
+ _NOTE: future versions will automate as much of the following steps as possible - but for now, this must be a manual process_
39
+
40
+ ### Installing the gem into your application
41
+
42
+ 1. Include the module in your `ApplicationController`
43
+
44
+ (this can either be the global `BuilderBase::ApplicationController` or just for one specific module if you prefer):
45
+
46
+ ```
47
+ class ApplicationController < ActionController::Base
48
+ include Builder::RailsCache
49
+ end
50
+ ```
51
+
52
+ 2. Enable caching locally in development mode, if `RAILS_CACHE_STORE` is given
53
+
54
+ In `config/environments/development.rb`, you should see a block something like this, usually around line 18 or so:
55
+
56
+ ```ruby
57
+ # Enable/disable caching. By default caching is disabled.
58
+ # Run rails dev:cache to toggle caching.
59
+ if Rails.root.join('tmp', 'caching-dev.txt').exist?
60
+ config.cache_store = :memory_store
61
+ config.public_file_server.headers = {
62
+ 'Cache-Control' => "public, max-age=#{2.days.to_i}"
63
+ }
64
+ else
65
+ config.action_controller.perform_caching = false
66
+ config.cache_store = :null_store
67
+ end
68
+ ```
69
+
70
+ Add another `elsif` clause to that block, so that it reads:
71
+
72
+ ```ruby
73
+ # Enable/disable caching. By default caching is disabled.
74
+ # Run rails dev:cache to toggle caching.
75
+ if Rails.root.join('tmp', 'caching-dev.txt').exist?
76
+ config.cache_store = :memory_store
77
+ config.public_file_server.headers = {
78
+ 'Cache-Control' => "public, max-age=#{2.days.to_i}"
79
+ }
80
+ # NEW LINES START HERE ----------------
81
+ elsif ENV['RAILS_CACHE_STORE'].present?
82
+ config.cache_store = ENV['RAILS_CACHE_STORE'].to_sym
83
+ # /END OF NEW LINES -------------------
84
+ else
85
+ config.action_controller.perform_caching = false
86
+ config.cache_store = :null_store
87
+ end
88
+ ```
89
+
90
+ 3. Enable caching in production mode, if `RAILS_CACHE_STORE` is given
91
+
92
+ Note: this code will enable caching in all deployed environments (dev, stage, uat, prod etc),
93
+ _but only if the RAILS_CACHE_STORE environment variable is present_ - so if you're cautious,
94
+ you can push the code first, and then do a separate MR to provide the config which actually enables the cache
95
+ in each environment, making it a simple job to revert it if anything goes wrong.
96
+
97
+ Add these lines to `config/environment/production.rb`, anywhere _inside_ the `Rails.application.configure do ... end` block:
98
+
99
+ ```ruby
100
+ if ENV['RAILS_CACHE_STORE'].present?
101
+ config.cache_store = ENV['RAILS_CACHE_STORE'].to_sym
102
+ end
103
+ ```
104
+
105
+ 4. Include the `Builder::RailsCache` module in your ApplicationController:
106
+
107
+ ```ruby
108
+ module BuilderBase
109
+ class ApplicationController
110
+ include Builder::RailsCache
111
+ end
112
+ end
113
+ ```
114
+
115
+ ## Usage
116
+
117
+ ### Adding response-caching to a controller method
118
+
119
+ For example, assume your controller method looks like this:
120
+
121
+ ```
122
+ def index
123
+ # Slow query:
124
+ @records = MyModelClass.where(....)
125
+ # maybe some other code is here too
126
+
127
+ # ultimately a response is rendered as JSON:
128
+ render json: @records.as_json, status: :ok
129
+ end
130
+ ```
131
+
132
+ You can add a `with_cache` block around everything involved in generating the JSON - constructing
133
+ queries, retrieving the data, calling any serializers, etc.
134
+
135
+ *NOTE* - The Rails cache ultimately stores _strings_ in Redis (or whatever other cache store you my have configured)
136
+ So you'll need to split the _conversion of the result to_ JSON, from the _rendering_ of the result back to
137
+ the caller, like this:
138
+
139
+ ```ruby
140
+ def index
141
+ json = with_cache do
142
+ @records = MyModelClass.where(....)
143
+ @records.to_json
144
+ end
145
+ render json: json, status: :ok
146
+ end
147
+ ```
148
+
149
+ #### Options / parameters
150
+
151
+ `with_cache` accepts the following parameters, all are *optional*:
152
+
153
+ ##### `:user_id`
154
+
155
+ This value will form the first part of the cache key
156
+
157
+ *Caching a user-specific response for each user*
158
+ Pass the current users' ID (e.g. `current_user.id`) to cache a different value for each user.
159
+ It's important to do this if anything in the code _inside_ the block (including within any serializers called, etc) references the current user
160
+
161
+ *Re-using the same cached value across all users*
162
+ Pass nil (or just don't supply the parameter, as *nil is the default*) to cache the same value across all users
163
+
164
+
165
+ ##### `:cache_time`
166
+
167
+ Determines expiry / TTL of the cache entry. If an entry is in the cache, but older than this value, it will be treated
168
+ as if there is no cache entry there at all.
169
+
170
+ *Default*
171
+ If no value is given, it will use the value of `ENV['RAILS_CACHE_TIMEOUT_SECONDS']`. If that environment
172
+ variable is not defined, or not parseable to an integer, it will default to zero - i.e. effectively disabling
173
+ the caching
174
+
175
+ *Specifying a number of seconds*
176
+ If the value is an integer, it will use that as the number of seconds for which the cache entry will be considered valid.
177
+
178
+ *Using a particular environment variable*
179
+ If the value is a string or symbol, it will append that string (uppercased) to `RAILS_CACHE_TIMEOUT_SECONDS` and look
180
+ for an environment variable with that name to use.
181
+ For example, if you pass `:short` or `:long` this will use the value of the `ENV['RAILS_CACHE_TIMEOUT_SECONDS_SHORT']` or `ENV['RAILS_CACHE_TIMEOUT_SECONDS_LONG)']` env vars - letting you have different cache timeouts for different methods.
182
+
183
+
184
+
185
+ ##### `:headers_to_include`
186
+
187
+ An array of header names, the values of which will be included in the key.
188
+ This might be useful if your application uses, for instance, a `language` header to render different strings
189
+
190
+
191
+
192
+ ##### `:key`
193
+
194
+ If a value is given, it will use that value as the cache key.
195
+ If no value is given (*default*), it will construct a key using a combination of :
196
+ * the given `user_id` (optional)
197
+ * the full request URL including all query parameters
198
+ * any headers specified in the given `headers_to_include` (optional).
199
+
200
+ If `user_id` is NOT given, then the same cache key will be used for all users (assuming they pass the same parameters and have the same values of the named headers), so make sure you consider this when introducing caching.
201
+
202
+ #### Error handling / returning non-200 status
203
+
204
+ The contents of the block are not called at all if there's a cache hit - so you may need to put a little thought into how to handle any non-OK status that you might want to return.
205
+
206
+ For example, this code -
207
+
208
+ ```
209
+ def show
210
+ @record = MyClass.find(params[:id])
211
+ render json: @record.to_json, status: :ok
212
+ end
213
+ ```
214
+
215
+ - has a potential edge case in the `.find` call. It will raise an `ActiveRecord::RecordNotFound` exception if the ID doesn't exist, which usually gets caught elsewhere and a 404 status returned. For this case, an exception will still bubble out of the block and be handled in the normal way, so this code should not need modifying.
216
+
217
+ But if your controller method decides on response status without raising an exception, modification may be needed.
218
+ For example:
219
+
220
+ ```ruby
221
+ def show
222
+ @record = MyClass.find(params[:id])
223
+ if @record.group_id != current_user.group_id
224
+ render json: { errors: ["You don't have permission to read that record"] }.to_json, status: :forbidden
225
+ else
226
+ render json: @record.to_json, status: :ok
227
+ end
228
+ end
229
+ ```
230
+
231
+ This code may need a slight alteration to handle this case, something like this:
232
+
233
+ ```ruby
234
+ def show
235
+ result = with_cache do
236
+ @record = MyClass.find(params[:id])
237
+ if @record.group_id != current_user.group_id
238
+ 'forbidden'
239
+ else
240
+ @record.to_json
241
+ end
242
+ end
243
+
244
+ if result == 'forbidden'
245
+ render json: { errors: ["You don't have permission to read that record"] }.to_json, status: :forbidden
246
+ else
247
+ render json: result, status: :ok
248
+ end
249
+ end
250
+ ```
251
+
252
+
253
+ ### Testing caching behaviour
254
+
255
+ #### Shared examples
256
+
257
+ The gem provides three shared examples, which you can add to your controller tests as follows:
258
+
259
+ Assuming your controller method looks like the example above,
260
+ you can use these shared examples in your specs like this:
261
+
262
+ ```ruby
263
+ describe 'GET :index' do
264
+ # define the object & method which your caching block
265
+ # surrounds:
266
+ let(:object_with_cache_miss_method) { MyModelClass }
267
+ let(:method_called_on_cache_miss) { :where }
268
+
269
+ # two user accounts, so that it can test the caching behaviour
270
+ # across different users accessing the same methods
271
+ let(:account_1) { ...user account object 1... }
272
+ let(:account_2) { ...user account object 2... }
273
+
274
+ # test the universal cache behaviour
275
+ it_behaves_like 'a cached method'
276
+
277
+ # ...and EITHER
278
+ it_behaves_like 'it has a different cache entry for each user'
279
+ # OR
280
+ it_behaves_like 'it has the same cache entry for all users'
281
+ end
282
+ ```
283
+
284
+ That will test for standard caching behaviour, using an expectation like:
285
+
286
+ `expect(object_with_cache_miss_method).to receive(:method_called_on_cache_miss)`
287
+
288
+ to signal a cache miss, and:
289
+
290
+ `expect(object_with_cache_miss_method).not_to receive(:method_called_on_cache_miss)`
291
+
292
+ to signal a cache hit.
293
+
294
+ You should ultimately get results that look something like this:
295
+
296
+ ```ruby
297
+ behaves like a cached method
298
+ caching
299
+ when the cache_timeout is more than zero
300
+ hitting the url twice for the same user with the same params
301
+ does not calls the code surrounded by with_cache the second time
302
+ returns the same response each time
303
+ after the cache expiry
304
+ calls the code surrounded by with_cache both times
305
+ hitting the url twice for the same user with different params
306
+ calls the code surrounded by with_cache both times
307
+ behaves like it has a different cache entry for each user
308
+ hitting the url twice for two different users with the same params
309
+ calls the code surrounded by with_cache both times
310
+
311
+ ```
312
+
313
+ ## Development
314
+
315
+ After checking out the repo, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
316
+
317
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
318
+
319
+ ## Contributing
320
+
321
+ Bug reports and pull requests are welcome on Builder's GitLab at https://gitlab.builder.ai/cte/alistair-davidson/builder-rails_cache.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/builder/rails_cache/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "builder-rails_cache"
7
+ spec.version = Builder::RailsCache::VERSION
8
+ spec.authors = ["Alistair Davidson"]
9
+ spec.email = ["alistair.davidson@builder.ai"]
10
+
11
+ spec.summary = "Provides convenience method `with_cache` for caching API response JSON"
12
+ spec.description = "Provides convenience method `with_cache` for caching API response JSON"
13
+ spec.homepage = "https://gitlab.builder.ai/cte/alistair-davidson/builder-rails_cache"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ # spec.metadata["allowed_push_host"] = "https://gem.fury.io/engineerai"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(__dir__) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ (File.expand_path(f) == __FILE__) ||
27
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
28
+ end
29
+
30
+ end
31
+ # make our shared examples available to projects which install the gem
32
+ spec.files += `git ls-files -- spec/shared_examples/*.rb`.split("\n")
33
+
34
+ # spec.bindir = "exe"
35
+ # spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ["lib"]
37
+
38
+ spec.add_dependency 'rails', '>= 4.0'
39
+ spec.add_development_dependency "byebug"
40
+
41
+ # For more information and examples about making a new gem, check out our
42
+ # guide at: https://bundler.io/guides/creating_gem.html
43
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Builder
4
+ module RailsCache
5
+ VERSION = "0.1.1"
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rails_cache/version"
4
+
5
+ module Builder
6
+ module RailsCache
7
+ class Error < StandardError; end
8
+
9
+ protected
10
+
11
+ # :cache_time determines expiry
12
+ # pass :short or :long to use the ENV['RAILS_CACHE_TIMEOUT_SECONDS_(SHORT|LONG)'] env vars
13
+ # or an integer to use a specific number of seconds
14
+ #
15
+ # :user_id will be the first part of the key
16
+ # Pass @token.id to cache a different value for each user
17
+ # or nil (default) to cache the same value across all users
18
+ #
19
+ # :key will default to nil, in which case a key will be constructed
20
+ # from the user_id, the url, and the headers_to_include
21
+ def with_cache(cache_time: :short, user_id: nil, key: nil, headers_to_include: [])
22
+ timeout = cache_timeout(cache_time)
23
+ key ||= cache_key(user_id: user_id, headers_to_include: headers_to_include)
24
+ logger.debug "cache key: #{key}, timeout: #{timeout}"
25
+ cache_hit = true
26
+
27
+ data = cache_instance.fetch(key, expires_in: timeout) do
28
+ cache_hit = false
29
+ yield if block_given?
30
+ end
31
+ logger.debug( cache_hit ? 'CACHE HIT' : 'CACHE MISS')
32
+ data
33
+ end
34
+
35
+ def cache_instance
36
+ Rails.cache
37
+ end
38
+
39
+ def cache_key(user_id: nil, headers_to_include: [])
40
+ headers = request.headers.select{|k,v| headers_to_include.include?(k)}.map{|k,v| [k,v].join('=')}.flatten.join('&')
41
+ [user_id, request.url, headers]
42
+ end
43
+
44
+ # pass a symbol or string to use the value of the ENV['RAILS_CACHE_TIMEOUT_SECONDS_(...)'] env var
45
+ # (e.g. if you pass :short, it will use ENV['RAILS_CACHE_TIMEOUT_SECONDS_SHORT'])
46
+ # pass an integer to use a specific number of seconds - if this 0, it's essentially a force-refresh
47
+ # the default is 0
48
+ def cache_timeout(short_long_or_seconds = nil)
49
+ if short_long_or_seconds.is_a?(Integer)
50
+ short_long_or_seconds
51
+ elsif short_long_or_seconds.is_a?(Symbol) || short_long_or_seconds.is_a?(String)
52
+ ENV[ ["RAILS_CACHE_TIMEOUT_SECONDS", short_long_or_seconds.to_s.upcase].join('_') ].to_i
53
+ else
54
+ 0
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+
61
+ # Make the shared examples available to projects which install this gem
62
+ # as per https://stackoverflow.com/a/50688950
63
+ if ENV['RAILS_ENV'] == 'test'
64
+ require File.expand_path('../../spec/shared_examples/cached_method.rb', __dir__)
65
+ end
@@ -0,0 +1,6 @@
1
+ module Builder
2
+ module RailsCache
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
@@ -0,0 +1,133 @@
1
+ #
2
+ # If your controller method looks like this:
3
+ # ```
4
+ # def index
5
+ # json = with_cache do
6
+ # @records = MyModelClass.where(....)
7
+ # @records.to_json
8
+ # end
9
+ # render json: json, status: :ok
10
+ # ```
11
+ #
12
+ # You can use this shared example in your specs like this:
13
+ #
14
+ # ```
15
+ # describe 'GET :index' do
16
+ # let(:object_with_cache_miss_method) { MyModelClass }
17
+ # let(:method_called_on_cache_miss) { :where }
18
+ #
19
+ # it_behaves_like 'a cached method'
20
+ # # and EITHER
21
+ # it_behaves_like 'it has a different cache entry for each user'
22
+ # # OR
23
+ # it_behaves_like 'it has the same cache entry for all users'
24
+ # end
25
+ # ```
26
+ #
27
+ # That will test for standard caching behaviour, using the expectation:
28
+ # `expect(object_with_cache_miss_method).to receive(:method_called_on_cache_miss)`
29
+ # to signal a cache miss, and:
30
+ # `expect(object_with_cache_miss_method).not_to receive(:method_called_on_cache_miss)`
31
+ # to signal a cache hit
32
+ #
33
+ RSpec.shared_examples "a cached method" do
34
+ describe 'caching' do
35
+ let(:token_1) { BuilderJsonWebToken.encode(account_1.id, 1.day.from_now, token_type: 'login') }
36
+ let(:token_2) { BuilderJsonWebToken.encode(account_2.id, 1.day.from_now, token_type: 'login') }
37
+
38
+ # default cache for test environment is null_store, which does not actually write data
39
+ # so we need to force usage of memory_store in these tests
40
+ let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) }
41
+ let(:cache) { Rails.cache }
42
+
43
+ before do
44
+ allow(Rails).to receive(:cache).and_return(memory_store)
45
+ Rails.cache.clear
46
+ end
47
+
48
+ context 'when the cache_timeout is more than zero' do
49
+ before do
50
+ allow(controller).to receive(:cache_timeout).and_return(1)
51
+ end
52
+
53
+ context 'hitting the url twice for the same user with the same params' do
54
+ let(:params) { {some_param: 3, token: token_1} }
55
+ before do
56
+ request.headers['token'] = token_1
57
+ end
58
+
59
+ it 'does not calls the code surrounded by with_cache the second time' do
60
+ expect(object_with_cache_miss_method).to receive(method_called_on_cache_miss).exactly(:once).and_return([])
61
+ get :current_conditions, params: params
62
+ get :current_conditions, params: params
63
+ end
64
+
65
+ it 'returns the same response each time' do
66
+ get :current_conditions, params: params
67
+ response_1 = response.body.dup
68
+ get :current_conditions, params: params
69
+ response_2 = response.body.dup
70
+ expect(response_1).to eq(response_2)
71
+ end
72
+
73
+ context 'after the cache expiry' do
74
+ it 'calls the code surrounded by with_cache both times' do
75
+ expect(object_with_cache_miss_method).to receive(method_called_on_cache_miss).exactly(:twice).and_return([])
76
+ get :current_conditions, params: params
77
+ sleep(1.1)
78
+ get :current_conditions, params: params
79
+ end
80
+ end
81
+ end
82
+
83
+ context 'hitting the url twice for the same user with different params' do
84
+ let(:params_1) { {some_param: 3} }
85
+ let(:params_2) { {some_param: 3, foo: 'bar'} }
86
+
87
+ it 'calls the code surrounded by with_cache both times' do
88
+ expect(object_with_cache_miss_method).to receive(method_called_on_cache_miss).exactly(:twice).and_return([])
89
+ request.headers['token'] = token_1
90
+ get :current_conditions, params: params_1
91
+ request.headers['token'] = token_1
92
+ get :current_conditions, params: params_2
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ RSpec.shared_examples 'it has a different cache entry for each user' do
100
+ let(:token_1) { BuilderJsonWebToken.encode(account_1.id, 1.day.from_now, token_type: 'login') }
101
+ let(:token_2) { BuilderJsonWebToken.encode(account_2.id, 1.day.from_now, token_type: 'login') }
102
+
103
+ context 'hitting the url twice for two different users with the same params' do
104
+ let(:params_1) { {some_param: 3} }
105
+ let(:params_2) { {some_param: 3} }
106
+
107
+ it 'calls the code surrounded by with_cache both times' do
108
+ expect(object_with_cache_miss_method).to receive(method_called_on_cache_miss).exactly(:twice).and_return([])
109
+ request.headers['token'] = token_1
110
+ get :current_conditions, params: params_1
111
+ request.headers['token'] = token_2
112
+ get :current_conditions, params: params_2
113
+ end
114
+ end
115
+ end
116
+
117
+ RSpec.shared_examples 'it has the same cache entry for all users' do
118
+ let(:token_1) { BuilderJsonWebToken.encode(account_1.id, 1.day.from_now, token_type: 'login') }
119
+ let(:token_2) { BuilderJsonWebToken.encode(account_2.id, 1.day.from_now, token_type: 'login') }
120
+
121
+ context 'hitting the url twice for two different users with the same params' do
122
+ let(:params_1) { {some_param: 3} }
123
+ let(:params_2) { {some_param: 3} }
124
+
125
+ it 'does not calls the code surrounded by with_cache for the second user' do
126
+ expect(object_with_cache_miss_method).to receive(method_called_on_cache_miss).exactly(:once).and_return([])
127
+ request.headers['token'] = token_1
128
+ get :current_conditions, params: params_1
129
+ request.headers['token'] = token_2
130
+ get :current_conditions, params: params_2
131
+ end
132
+ end
133
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: builder-rails_cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Alistair Davidson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Provides convenience method `with_cache` for caching API response JSON
42
+ email:
43
+ - alistair.davidson@builder.ai
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".rspec"
49
+ - CHANGELOG.md
50
+ - README.md
51
+ - Rakefile
52
+ - builder-rails_cache.gemspec
53
+ - lib/builder/rails_cache.rb
54
+ - lib/builder/rails_cache/version.rb
55
+ - sig/builder/rails_cache.rbs
56
+ - spec/shared_examples/cached_method.rb
57
+ homepage: https://gitlab.builder.ai/cte/alistair-davidson/builder-rails_cache
58
+ licenses: []
59
+ metadata:
60
+ homepage_uri: https://gitlab.builder.ai/cte/alistair-davidson/builder-rails_cache
61
+ source_code_uri: https://gitlab.builder.ai/cte/alistair-davidson/builder-rails_cache
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 2.6.0
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubygems_version: 3.0.3
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Provides convenience method `with_cache` for caching API response JSON
81
+ test_files: []