<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>kobe (kobe)</title>
    <link>https://ruby-china.org/kobe</link>
    <description/>
    <language>en-us</language>
    <item>
      <title>Rails.cache 相关知识</title>
      <description>&lt;p&gt;可能里面的一些知识已经不被大家使用了，但是作为学习，我想和大家分享一下个人关于 Rails.cache 的浅显的认识，望大家指教。&lt;/p&gt;
&lt;h2 id="1.Rails.cache是什么"&gt;1.Rails.cache 是什么&lt;/h2&gt;
&lt;p&gt;它是 Rails 中的缓存，拥有所有缓存的共同点，它是为了提升网站性能。&lt;/p&gt;
&lt;h2 id="2.Rails中Rails.cache的存储系统。"&gt;2.Rails 中 Rails.cache 的存储系统。&lt;/h2&gt;
&lt;p&gt;本身常用的有四种，可以根据不同的环境进行选择不同的存储系统。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FileStore，利用文件系统缓存文件，能够在多个应用间共享缓存，但是这样会不断的增加硬盘使用。&lt;/li&gt;
&lt;li&gt;MemoryStore,  Ruby 进程使用共同的内存，默认大小为 32M，，虽然可以更改这个限制，但是不适合大型的部署，并且它不能用于多个应用共享缓存。&lt;/li&gt;
&lt;li&gt;MemCacheStore, 这种方式使用 Memcached 最为后端缓存服务，它提供了高性能的、集中式的缓存服务，可以在多个应用间共享缓存，这是一种适合中大型商业应用的选择。&lt;/li&gt;
&lt;li&gt;NullStore,  适合开发和测试环境的配置，它不会储存任何东西，但是可以正常调试 Rails.cache 中的方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3. Rails项目的自定义配置存储系统。"&gt;3. Rails 项目的自定义配置存储系统。&lt;/h2&gt;
&lt;p&gt;这里我以使用 redis 来作为 Rails.cache 的存储系统进行介绍&lt;/p&gt;
&lt;h4 id="3.1 为什么会选redis"&gt;3.1 为什么会选 redis&lt;/h4&gt;
&lt;p&gt;因为是 key-value 的结构，同时使用 redis，能够通过 redis 的命令快速实现，比关系型数据库拥有更快的读写速度，且更适合储存非结构化数据。&lt;/p&gt;
&lt;h4 id="3.2 如何配置"&gt;3.2 如何配置&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;确保你的系统已经安装了 redis 数据库（具体怎么安装，这里不做阐述）&lt;/li&gt;
&lt;li&gt;在你的 gemfile 文件中，加入 gem 'redis-rails'这一行，然后 bundle install。&lt;/li&gt;
&lt;li&gt;一般初始化的默认配置可以在 development.rb,production.rb,test.rb 文件中单独设置适用于不同环境的存储系统；我选择直接在 application.rb 中写配置信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;配置信息（必须）：
config.action_controller.perform_caching = true # 确保开启缓存，dev环境下默认是没有开启的。
config.cache_store = :redis_store, {
    host: 'localhost',
    port: '6379',
    db: 1, # 这是整数，可以理解为redis数据库中的表标志，默认是16个数据库，可从0-15中取值
    password: '',
    expires_in: 5.hours # 过期时间的设置
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="4. Rails.cache常见用法"&gt;4. Rails.cache 常见用法&lt;/h2&gt;&lt;h4 id="4.1 首先如何设置开启缓存"&gt;4.1 首先如何设置开启缓存&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;production 上默认开启了缓存&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;development 上默认不开启&lt;/p&gt;

&lt;p&gt;配置方法一（常用）：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 在development.rb文件中添加
config.action_controller.perform_caching = true
# 设置缓存的页面存放的地址(不能修改，默认是public)
config.action_controller.page_cache_directory = "#{Rails.root.to_s}/public"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置方法二（Rails5 版本之后开始支持）：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 执行任务，会在tmp文件下创建caching-dev.txt和restart.txt文件
rake dev:cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经过个人测试，两者不能混用，混用存在的问题：
1.如果你使用 rake dev:cache，就不能在 development.rb 中去修改缓存默认存储的地址，一旦修改，缓存就会失效。
2.一旦你是用 rake dev:cache 来开启缓存，那么就要使用 rake dev:cache 来关闭缓存（不能通过 config.action_controller.perform_caching = false 来操作，无法起作用），如果要自己测试，那你一定要首先把之前缓存的文件给删除掉，不然不管你怎么操作，只要 public 下有该文件，就一直读该文件。&lt;/p&gt;

&lt;p&gt;如果看一下 rake dev:cache 的源码，我们能找到另外一种方式来关闭&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 源码 rake任务
namespace :dev do
    desc "Toggle development mode caching on/off"
    task :cache do
        Rails::DevCaching.enable_by_file
    end
end
# 源码：通过文件来判断是否开启缓存
FILE = "tmp/caching-dev.txt"
def enable_by_file
    FileUtils.mkdir_p("tmp")

    if File.exist?(FILE)
      delete_cache_file
      puts "Development mode is no longer being cached."
    else
      create_cache_file
      puts "Development mode is now being cached."
    end

    FileUtils.touch "tmp/restart.txt"
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以，很明显，我们可以通过删除 tmp 下的 restart.txt 和 cache-dev.txt 来关闭缓存。
个人建议：还是在 development.rb 文件中自己配置比较灵活&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="4.2 如何使用3种缓存方式（片段缓存，页面缓存，方法缓存）"&gt;4.2 如何使用 3 种缓存方式（片段缓存，页面缓存，方法缓存）&lt;/h4&gt;
&lt;p&gt;从 Rails4 开始，页面缓存和方法缓存已经转换为 gem 的形式，只有片段缓存是 Rails 默认的。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;页面缓存&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;一句话总结：使用缓存的页面来代替 action 请求对应的页面，这个和缓存系统无关。
默认缓存的文件直接放在 public 目录下。&lt;/p&gt;

&lt;p&gt;页面缓存现在已经被单独作为一个 gem，需要在你的 Gemfile 中加入 gem "actionpack-page_caching"&lt;/p&gt;

&lt;p&gt;真正的代码实现：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 一个控制器
class HuanCunController &amp;lt; ApplicationController
    # 使用缓存
    caches_page :welcome_show

    # 缓存的页面对应的控制器
    def welcome_show

    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;welcome_show 页面
    
        Hello,welcom!!
        current_time_now:&amp;lt;%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %&amp;gt;
    &lt;/p&gt;

&lt;p&gt;没有使用缓存的时候，每次请求的页面都是实时变化的，可以看 current_time_now 的值。
    使用缓存后，会在你配置保存目录的文件下生成对应的静态 html 文件。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;方法缓存&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在 Gemfile 文件中加入 gem 'actionpack-action_caching'
为了便于观察，选择 redis 作为缓存系统。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;使用方法缓存的代码如下：
    class Car::CarsController &amp;lt; ApplicationController
      caches_action :index
      def index

      end
    end      
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;监控方法：&lt;/p&gt;

&lt;p&gt;打开终端，输入 redis-cli，然后输入 monitor，可以监控 redis 的存储情况。
    调用该 index 方法，会产生一个 key："get""views/locahost:3003/car/cars"&lt;/p&gt;

&lt;p&gt;以后每次再去调用该 index，你会发现 redis 的 monitor 中都是显示如下信息：说明缓存成功，不再每次去方法中执行，而是直接从 redis 中去取。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1560408837.780396 [2 [::1]:54380] "get" "views/localhost:3003/car/cars"
1560408838.140465 [2 [::1]:54380] "get" "views/localhost:3003/car/cars"
1560408838.667096 [2 [::1]:54380] "get" "views/localhost:3003/car/cars"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;过期时间的问题：&lt;/p&gt;

&lt;p&gt;如果你没有设置过期时间，那么他的过期时间使用 redis 设置的过期时间。&lt;/p&gt;

&lt;p&gt;如果想查看过期时间，进入 redis 控制台，然后选择你使用的数据库 id，例如 (查出来的时间是以秒为单位)&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;myMacBook-Pro redis-cli
127.0.0.1:6379&amp;gt;select 2
OK
127.0.0.1:6379[2]&amp;gt; TTL "views/localhost:3003/car/cars"
(integer) 13620
127.0.0.1:6379[2]&amp;gt;=
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想自己设置过期时间，可以直接查看 gem 'actionpack-action_caching'这个 gem 的文档&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;片段缓存
片段缓存是 rails 中最常用的一种缓存方式，主要是在页面中进行局部缓存。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 在index.html.erb页面中
 &amp;lt;% cache 'test_index' do %&amp;gt;
 &amp;lt;%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个其实和方法缓存的监控的方式一样，你会发现会生成"views/car/cars/index:61696bc621e5ee68531c6a58dfaf4da3/test_index"这样的 key，同时也能查到过期时间。
  每次你去刷新页面，都会在 redis 中去请求这个 key 值对应的 value 值。
  如果想自己设置过期时间为 2 小时，可以这样设置&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;% cache 'test_index'，expires_in: 2.hours do %&amp;gt;
 &amp;lt;%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你想让这个"views/car/cars/index:61696bc621e5ee68531c6a58dfaf4da3/test_index"的 key 失效，你可以使用 expire_fragment('views/car/cars/index:61696bc621e5ee68531c6a58dfaf4da3/test_index') ，但是在实际应用中我们无法查到这个 key 的具体值，所以我们可以这样设置：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;% cache 'test_index', {skip_digest: true} do %&amp;gt;
 &amp;lt;%= Time.now.strftime('%Y-%m-%d %H:%M:%S.%L') %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样’test_index’将会被作为 cache key 被缓存起来，如果想要使他失效，只要在对应的 action 里调用就 expire_fragment('test_index') 就行，如果不加 {skip_digest: true}，那么是无法直接调用 expire_fragment('test_index') 的。
可以简单的查看一下生成这个片段 name 的源码：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
        if skip_digest
          name
        else
          fragment_name_with_digest(name, virtual_path)
        end
end
可以很明显的看出，如果skip_digest是true，将直接返回页面中写的name。
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>kobe</author>
      <pubDate>Fri, 21 Jun 2019 16:18:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/38711</link>
      <guid>https://ruby-china.org/topics/38711</guid>
    </item>
  </channel>
</rss>
