Setup
I'm aware of how to do a Rails.exist
? Rails.read
: fetch & rails.write
but rails has a nice Rails.cache.fetch
syntax that will automatically check if the cache key exists and is valid, return that if true, else run through the block and save to the cache.
Examples
For example (long way)
def search(param1)
if Rails.cache.exist?("key", namespace: "example")
response = Rails.cache.read("key", namespace: "example")
else
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: param1 }
end
Rails.cache.write("key", response, namespace: "example", expires_in: 1.hour) if response.success?
end
response
end
Short hand using fetch syntax
Rails.cache.fetch("key", namespace: "example") do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: value }
end
response
end
This nice short hand does the same thing as the long way, except for the if response.success?
which is what I'm interested in. If I make a call to this api, and the response is a 400 with a body of {"error": "invalid value for <key>"}
the short way will cache that error response, which is no good. Edit for clarity: I do want that response body with the error, but I don't want to cache.
Question
Does anyone know of a way to pass a lambda or something to conditionally cache using the shorthand fetch
syntax? I'd rather not have this method return nil when the cache fails because I want that error message in the response body, and deleting the cache if the response isn't a success seems to defeat the purpose of the entire thing (unless it's faster?)
CodePudding user response:
How I've done it using fetch
syntax
def search(param1:)
bailed_resp = nil
cached_resp = Rails.cache.fetch("key", namespace: "example", skip_nil: true, expires_in: 1.hour) do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: param1 }
end
# Save the response for later and bail on caching unless response.success is true
bailed_resp = response
break unless response.success?
response
end
# If we bailed on the fetch, use the bailed response, otherwise use the new/fetched cache.
cached_resp == nil ? ResponseWrappers::Service.new(bailed_resp) : ResponseWrappers::Service.new(cached_resp)
end
Though this does work, I fail to see how it's any different than the long form syntax, which for reference:
def search(param1:)
if Rails.cache.exist?("key", namespace: "example")
response = Rails.cache.read("key", namespace: "example")
else
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: param1 }
end
Rails.cache.write("key", response, namespace: "example", expires_in: 1.hour) if response.success?
end
response
end
Is anyone able to give additional information on the differences between the two and/or if it's negligible?
CodePudding user response:
You can just break from this block
Rails.cache.fetch("key", namespace: "example") do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: value }
end
break unless response.success?
response
end
In this case nothing will be written by this key for failure response
But if you try to repeat this code and response will be ok, it will be written
If you want to use this construction in some method and need this method to return response, you change it to:
def search
Rails.cache.fetch("key", namespace: "example") do
conn = faraday_helper(url: "search/url")
response = conn.post do |req|
req.body = { key: value }
end
return response unless response.success?
response
end
end
And process result outside the method