Search code examples
ruby-on-railscaching

Rails daily cache block not working in production


In a ruby on rails 6 app, I want to display a daily quote using a daily cache block. I tried two options:

In controller:

@quote_of_the_day = Rails.cache.fetch("daily_quote_#{Date.today}", expires_in: 1.day) do
    Quote.joins(:quote_tags).where(quote_tags: { id: 1 }).order("RANDOM()").limit(1).first
end

In the view:

<% cache("daily-quote-#{Date.today}", expires_in: 24.hours) do %>
            <blockquote>
                <%= @quote_of_the_day.content.html_safe %>
                <figcaption>
                    <% if @quote_of_the_day.book.present? %>
                        <% if @quote_of_the_day.author.present? %>
                            <%= @quote_of_the_day.author %> — <cite><%= @quote_of_the_day.book %></cite>
                        <% else %>
                            <cite><%= @quote_of_the_day.book %></cite>
                        <% end %>
                    <% elsif @quote_of_the_day.author.present? %>
                        <%= @quote_of_the_day.author %>
                    <% end %>
                </figcaption>
            </blockquote>
        <% end %>

It works well in development. But, in production, the quote is updated at each request… You can see it live on this page.

Here is the config/production.rb file:

config.cache_classes = true
config.action_controller.perform_caching = true
default_expiration = 24.hours.to_i
config.cache_store = :redis_cache_store, { url: "redis://#{ENV['REDIS_CERES_ADDRESS']}", expires_in: default_expiration }
config.action_mailer.perform_caching = false

I wonder what I am doing wrong here. The cache with a unique key using the Date.today should be cached and updated every day. Thanks for your help.


Solution

  • 1. About cache options

    The better way is using both:

    Use daily_quote_#{Date.today} as cache key in the controller to avoid querying quote every request:

    @quote_of_the_day = Rails.cache.fetch("daily_quote_#{Date.today}", expires_in: 1.day) do
      xxx
    end
    

    And use @quote_of_the_day as cache key in the view to improve render speed:

    <% cache(@quote_of_the_day) do %>
      xxx
    <% end %>
    

    2. About cache is not working

    It works well in development means cache setting code should be ok;

    the quote is updated at each request means cache in controller is not working in production.

    So the issue may be the Redis config in production.

    You could verify if cache and Redis works in production on console:

    # Rails console
    
    # 1. Execute the following code multiple times to see if the result is same
    Rails.cache.fetch(Date.today, expires_in: 1.day) { Time.now }
    
    # 2. And try to use Redis directly
    redis = Redis.new(url: redis_url)
    
    redis.set(Date.today, Time.now)
    redis.get(Date.today)