Rails 5.2.1 - Model & Fragment Caching

和自甴很熟 提交于 2021-01-29 09:23:20

问题


I am trying to setup Model and Fragment Caching in Rails 5.2.1

I have had success with Fragment caching, but I am still seeing database queries after implementing model caching for my Model.

I have enabled development caching

$ rails dev:cache

Model Helper

module LanguagesHelper
  def approved_languages
    Rails.cache.fetch("approved_languages") { Languages.is_active.is_approved }
  end
end

Controller

class LanguagesController < ApplicationController
  include LanguagesHelper

  def index
    @languages = approved_languages
  end
end

Views

app/views/languages/index.html.erb

<%= render partial: 'languages/language', collection: @languages, cached: true %>

app/views/languages/_language.html.erb

<% cache language do %>
  <%= language.name %>
<% end %>

Console

Started GET "/languages" for 127.0.0.1 at 2018-08-21 14:13:29 -0400
Processing by LanguagesController#index as HTML
  Rendering languages/index.html.erb within layouts/application
  Language Load (1.2ms)  SELECT "languages".* FROM "languages" WHERE "languages"."deleted" = $1 AND "languages"."approved" = $2  [["deleted", false], ["approved", true]]
  ↳ app/views/languages/index.html.erb:4
  Rendered collection of languages/_language.html.erb [1 / 1 cache hits] (3.0ms)
  Rendered languages/index.html.erb within layouts/application (10.9ms)
Completed 200 OK in 50ms (Views: 46.2ms | ActiveRecord: 1.2ms)

Why am I still seeing database queries with each request?


回答1:


What seems to be going on here is that you're caching the relation before it loads the records, and so it still has to actually load them before it can be used (using my Ad model because it's there and convenient for testing in irb):

ads = Ad.all;nil # no query here, this is what I think you're caching
# this next line is where the query is run, (this would be
# equivalent to your render line)
ads.each { ... } 
#  Ad Load (0.1ms)  SELECT "ads".* FROM "ads"

instead you might try forcing active record to load the relation before you cache it and see if that helps. You can do this by using load:

ads = Ad.all.load;nil # query is now run here
#  Ad Load (0.1ms)  SELECT "ads".* FROM "ads"
ads.each { ... } # and not run here

and together with caching enabled (all in a single rails console session, multiple sessions seems to forget the cache from the previous, but I've not configured caching so probably just an in-memory store of some kind)

ads = Rails.cache.fetch("test load") { Ad.all.load };nil # query
#  Ad Load (0.9ms)  SELECT "ads".* FROM "ads"
ads = Rails.cache.fetch("test load") { Ad.all.load };nil # no query
ads.each {  } # no query
ads = Rails.cache.fetch("test without load") { Ad.all };nil # no query
ads.each { };nil # query
#  Ad Load (0.1ms)  SELECT "ads".* FROM "ads"
ads = Rails.cache.fetch("test without load") { Ad.all };nil # no query
ads.each { };nil # query
#  Ad Load (0.1ms)  SELECT "ads".* FROM "ads"



回答2:


I was close before but now have successfully implemented caching. The above answer was appreciated but not what I was looking for, this is my current setup.

I was calling the Language model query in a Helper module when I should have moved it to the model.

Model

after_save :clear_cache
after_destroy :clear_cache

def clear_language_cache
  Rails.cache.delete('Language.active.approved')
end

def self.active_approved
  Rails.cache.fetch('Language.active.approved') { is_active.is_approved.order(created_at: :desc).to_a }
end

Controller

class LanguagesController < ApplicationController
  def index
    @languages = Language.active_approved
  end
end

Console

Started GET "/languages" for 127.0.0.1 at 2018-08-22 18:13:21 -0400
Processing by LanguagesController#index as HTML
  Rendering languages/index.html.erb within layouts/application
  Rendered collection of languages/_language.html.erb [1 / 1 cache hits] (11.0ms)
  Rendered languages/index.html.erb within layouts/application (15.9ms)
Completed 200 OK in 68ms (Views: 45.5ms | ActiveRecord: 5.8ms)


来源:https://stackoverflow.com/questions/51954529/rails-5-2-1-model-fragment-caching

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!