ruby-on-railscachingfragment-caching

rails4 after caching query still runs


I have a rails 4 app and trying to implement caching. I use the @profiles_sidebar.first cache key for checking if new user was created. I'm not sure if this is ok, since there still is a db query. Is this the preferred mechanism to check if caching needs to be expired? Am I doing well?

<% cache(@profiles_sidebar.first) do %>
  <% @profiles_sidebar.each do |profile| %>
    <%= link_to user_path(profile.user) do %>            
      <%= truncate(profile.full_name, length: 25) %>
      <%= truncate(profile.company, length:25) %>
    <% end %>
  <% end %>
<% end %>

console code when reading cache:

13:31:53 puma.1    |   Profile Load (2.2ms)  SELECT  "profiles".* FROM "profiles"  ORDER BY "profiles"."created_at" DESC LIMIT 1
13:31:53 puma.1    |   User Load (2.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (67)
13:31:53 puma.1    |   Cache digest for app/views/users/_user_sidebar.html.erb: bfc9447057c94bcfe13c18e391127f2d
13:31:53 puma.1    | Read fragment views/profiles/62-20160331112332689423000/bfc9447057c94bcfe13c18e391127f2d (0.2ms)
13:31:53 puma.1    |   Rendered users/_user_sidebar.html.erb (11.8ms)

Solution

  • There is no way of getting around at least one database query since you need to know if the record has been updated since the digest was created.

    You could load @profiles_sidebar sidebar upfront which would be somewhat better on a "cold" cache since its a single DB query:

    @profiles_sidebar = Profile.order(created_at: :desc)
                               .limit(10)
                               .load
    

    The actual difference between fetching a single record and 10 may be marginal though.

    You also may want to use eager loading or includes to fetch both User and Profile in one query:

    @profiles_sidebar = Profile.includes(:user)
                               .order(created_at: :desc)
                               .limit(10)
                               .load