0

I am using fragment caching in order to speed up the rendering time of Comfortable Mexican Sofa. However, I cannot figure out how to get it to expire the cache for a particular object when I update it.

I am using Comfy as a CMS for a company website that I am building. To allow for dynamic page content I have set it up so it renders directories of pages as blocks of content.

class WelcomeController < ApplicationController
  def index
    @testimonials = Comfy::Cms::Page.find_by_full_path!("/testimonials").children
    @clients = Comfy::Cms::Page.find_by_full_path!("/clients").children
    @recent_blogs = Comfy::Cms::Page.find_by_full_path!("/blog").children.published.last(4)
    @team = Comfy::Cms::Page.find_by_full_path!("/team").children
  end

end

I am then rendering the collections using the cms_block_content helpers given by CMS.

<% @clients.each do | client |%>
    <img class="client__logo lazy" data-original="<%=cms_block_content(:client_logo, client).file.url%>">
<%end%>

I also introduced some fragment caching as all the inline rendering was massively slowing down the loading of the page.

However, I have run into a problem. When I create or delete new content it appears/disappears on the page fine, however, when I update content the content on the page doesn't update. Updating content doesn't seem to expire the cached content (if you run Rails.cache.clear then the updated content loads).

I looked into creating a cache sweeper as posited in the CMS documentation but I wasn't quite sure how to proceed as I am not sure what parameters to pass through to the actual expire_fragment method.

class CmsAdminSweeper < ActionController::Caching::Sweeper
  observe Comfy::Cms::Page

  def after_update(record)
    do_sweeping(record)
  end

  def do_sweeping(record)
    # return unless modification is made from controller action
    return false if session.blank? || assigns(:site).blank?

    Rails.logger.info("CmsAdminSweeper.do_sweeping in progress...")

    expire_fragment({ controller: '/welcome', action: 'index', id: record.id})
  end
end

Is this the best way to proceed? If so, what can I pass through to the expire_fragment method?

Many thanks!

Tom

thrgamon
  • 438
  • 1
  • 5
  • 14
  • This is the hard way to do it.I don't know this cms, but would be easier to create some cache keys in the view and save them in redis. Then when you change the object key will be updated and the next request will see that the cache keys don't match and the view gets reloaded with the new data. – Sean Magyar Jan 27 '17 at 17:46
  • Hey @SzilardMagyar, thanks for the help. I am not quite sure what you mean, would you be able to point me in the direction of either a SO question, some documentation or a tutorial demonstrating how to do this or something similar? – thrgamon Jan 28 '17 at 22:36
  • Here in the fragment/russian-doll-caching part: http://guides.rubyonrails.org/caching_with_rails.html – Sean Magyar Jan 30 '17 at 23:16
  • Thanks for the link! I have now tried implementing key based caching, but in order to do so I had to monkey patch the gem's model and then that opened up a whole new bag of worms, so I have had to go with the sweeper just using `Rails.cache.clear` instead of clearing just the fragment as a work around. – thrgamon Feb 02 '17 at 17:08

1 Answers1

1

The correct answer had in fact been staring me in the face the entire time, I just didn't quite realise it. All I needed to do was pass in the record.

expire_fragment(record)

However, the reason that it wasn't working when I first tried it was due to the fact that a digest is added to the cache when it is saved. This means that you cannot expire them manually. Therefore, when you cache the view you need to make sure that you are skipping the digest.

<% @clients.each do | client |%>
     <% cache client, skip_digest: true do %>
          <img class="client__logo lazy" data-original="<%=cms_block_content(:client_logo, client).file.url%>">
     <%end%>
 <%end%>

Et voila! It works.

Community
  • 1
  • 1
thrgamon
  • 438
  • 1
  • 5
  • 14