This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the caching category.
Last Updated: 2024-11-21
I wrote the following code and it executed just fine. This was despite the fact that, as I would later learn, it had an error:
@taxonomies = Rails.cache.fetch("taxons_db_data_#{current_store}") do
Taxonomy.includes(:taxon) # should have been :taxons (plural)
end
My first hint that there was a bug here was that downstream code consuming this
@taxonomies
instance variable failed - the bug essentially was deferred until
this data structure was consumed. I saw the issue and fixed the incorrect pluralization:
@taxonomies = Rails.cache.fetch("taxons_db_data_#{current_store}") do
Taxonomy.includes(:taxons) # now plural
end
Desite my fix, the bug continued. This seemed weird because usually a cache doesn't store errors - i.e. this would not be cached.
@taxonomies = Rails.cache.fetch("taxons_db_data_#{current_store}") do
raise
end
When I experimented with clearing the cache, however, my code worked again,
indicating that the cached entity was the source of my woes. And so I got to the
bottom of it. The issue was that Rails scopes (i.e. code that executes SQL such
as Taxonomy.include()
) are lazy, so therefore the error doesn't actually
crop up until you call .to_a
(explicitly or implicitly) on it - which only happens
upon consumption of the taxonomies array.
I can prove this laziness by looking at what the postgres server (not the Rails client logs, which cannot be fully trusted) see when I cache this way:
taxonomies = Rails.cache.fetch("test123") { Taxonomy.includes(:taxons) }
# postgres server: executes every time - i.e. even though it is correct, it is not cached.
taxonomies = Rails.cache.fetch("test123") { Taxonomy.includes(:taxons).to_a }
# postgres server: DOES NOT execute every time, i.e. it caches