{"id":2618,"date":"2018-01-09T18:38:46","date_gmt":"2018-01-10T00:38:46","guid":{"rendered":"http:\/\/www.mooreds.com\/wordpress\/?p=2618"},"modified":"2018-01-09T18:39:07","modified_gmt":"2018-01-10T00:39:07","slug":"the-rails-cache","status":"publish","type":"post","link":"https:\/\/www.mooreds.com\/wordpress\/archives\/2618","title":{"rendered":"The Rails Low Level Cache"},"content":{"rendered":"<p>I think the <a href=\"http:\/\/guides.rubyonrails.org\/caching_with_rails.html#low-level-caching\">Rails low level cache<\/a> is the bees knees. It lets you store complicated values easily, manage TTLs, and improve the performance of your application.<\/p>\n<p>I&#8217;d be remiss in stating that you shouldn&#8217;t cache until you need to.\u00a0 Caches will introduce additional complexity into your application, make troubleshooting harder, and in general can be confusing.\u00a0 How do you know if you need to introduce a cache?\u00a0 <strong>Profile<\/strong>.\u00a0 Using <a href=\"https:\/\/github.com\/MiniProfiler\/rack-mini-profiler\">rack-mini-profiler<\/a> is a great quick and dirty way to profile your code.<\/p>\n<p>The rails low level cache is fairly simple to configure (especially if you&#8217;re using a PaaS like Heroku&#8211;you can drop in a <a href=\"https:\/\/www.memcachier.com\/\">managed memcached service<\/a> easily).<\/p>\n<p>From there, you need to build a cache key.\u00a0 This is a string, up to <a href=\"https:\/\/stackoverflow.com\/questions\/42299664\/what-is-the-max-key-length-and-max-size-of-value-in-memcached\/42303647\">250 characters in length<\/a>, that uniquely identifies whatever you&#8217;re trying to cache.\u00a0 Basically anything that would cause a change in the contents of the cached object should be included in this key.\u00a0 However, since you are going to calculate this key every time the value is requested, you don&#8217;t want the cache key to be expensive to calculate, otherwise the value of the cache will be degraded.\u00a0 Good things for the key: timestamps, max <code>updated_at<\/code> values for a collection, user ids or roles.<\/p>\n<p>Then, putting a value in the cache is as easy as:<\/p>\n<pre>def pull_from_cache\r\n  cache_key = 'mykeyval'\r\n  myval = Rails.cache.fetch(cache_key, expires_in: 1.hours) do\r\n      @service.build_expensive_object()\r\n  end\r\nend\r\n<\/pre>\n<p>In the case above, the cached value will automatically expire in 1 hour.\u00a0 If you don&#8217;t set the expiration time, then the cached value will eventually be removed via <a href=\"https:\/\/stackoverflow.com\/questions\/4962290\/memcached-lru-and-expiry\">LRU<\/a>.\u00a0 How long that is depends on the size of your cache and what else you are putting in there.<\/p>\n<p>If you want to test that something is being put in the cache, you can run a unit test and see how many times <code>build_expensive_object()<\/code> is called.<\/p>\n<pre>#...\r\nobject.service = @service\r\nexpect(@service).to receive(:build_expensive_object).once\r\nobject.pull_from_cache  \r\nobject.pull_from_cache\r\n#...\r\n<\/pre>\n<p>In a production troubleshooting situation, you may need to evict something from the cache.\u00a0 You can do so from the rails console by finding the cache key and running <code>Rails.cache.delete('key')<\/code>.<\/p>\n<p>Using the low level cache is a great way to push read heavy hot spots of your rails application (database queries or other complicated calculations) into memory and make your application faster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I think the Rails low level cache is the bees knees. It lets you store complicated values easily, manage TTLs, and improve the performance of your application. I&#8217;d be remiss [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[77],"tags":[],"class_list":["post-2618","post","type-post","status-publish","format-standard","hentry","category-rails"],"_links":{"self":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts\/2618","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2618"}],"version-history":[{"count":4,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts\/2618\/revisions"}],"predecessor-version":[{"id":2622,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/posts\/2618\/revisions\/2622"}],"wp:attachment":[{"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2618"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2618"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mooreds.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2618"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}