Fragment Caching

Episode #24 by Teacher's Avatar David Kimura

Summary

Make your application faster by leveraging memory and caching fragments of your view.
rails caching performance 7:07

Resources

Summary

# development.rb
    config.action_controller.perform_caching = true
    config.cache_store = :dalli_store, 'localhost'

# _story.html.erb
    <% cache story do %>
      <%= content_tag :li, class: 'list-group-item' do %>
        <h5><%= story.name %></h5>
        <p><%=h raw story.content %></p>
        <div class='row'>
          <div class='col-xs-8'>
            <% story.tag_list.each do |tag| %>
              <%= content_tag :span, tag, class: 'label label-primary' %>
            <% end %>
            <%= link_to 'Edit', edit_story_path(story), class: 'label label-info' %>
          </div>
          <div class='col-xs-4'>
            <div class='pull-right'><em>created <%= time_ago_in_words story.created_at %></em></div>
          </div>
        </div>
      <% end %>
      <% sleep 0.1 # Crazy Long Running Process %>
    <% end %>

# stories/index.html.erb
    <% @most_tagged.each do |tag| %>
      <% cache ['tag', tag.try(:name)], skip_digest: true do %>
        <li class='list-group-item'><%= "#{tag.try(:name).try(:titleize)} (#{tag.taggings_count})" %></li>
      <% end %>
    <% end %>

# config/initializers/active_record_base.rb
    class ActiveRecord::Base
      def expire_fragment(*args)
        ActionController::Base.new.expire_fragment(*args)
      end
    end

Update:  Thank you /u/danshep for pointing this out.

# model/story.rb
    # before_update :expire_changed_tags, if: :tag_list_changed?
    before_save :expire_changed_tags, if: :tag_list_changed?
    private
    def expire_changed_tags
      original_tag_list = self.tag_list_change.first
      new_tag_list = self.tag_list_change.last
      modified_tags = original_tag_list - new_tag_list | new_tag_list - original_tag_list
      modified_tags.each do |tag|
        self.expire_fragment "tag/#{tag}"
      end
    end