> For the complete documentation index, see [llms.txt](https://kelby.gitbook.io/rails-beginner-s-guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kelby.gitbook.io/rails-beginner-s-guide/actionview_helper_method/actionview_helper_methods_introduction/helper_cache_helper/say_cache.md).

# 片段缓存和 Cache Key

1\) 页面上的静态内容

2\) 页面上的动态内容

3\) 页面上的内容，在 model 层面有关联

4\) 页面上的内容有嵌套关系

## 使用片段缓存几点原则

1. 缓存由动态内容和静态内容两部分构成。
2. 动态内容的 cache\_key 由我们指定； 2. 没有嵌套的情况下，如果动态内容不指定 cache\_key，则自己的动态内容永远不会更新(例外见最后)； 2. 有嵌套的情况下，如果动态内容不指定 cache\_key，则自己的动态内容 & 孩子的动态内容永远不会更新(例外见最后)；
3. 没有嵌套的情况下，有且只有自己的 cache\_key 更新，动态内容才更新；
4. 有嵌套的情况下，有且只有自己的 cache\_key 更新 & 父亲的 cache\_key 更新，动态内容才更新；
5. 动态内容的更新，不影响静态内容的部分；
6. (各动态内容的 cache\_key 是独立的，自己及其父亲、兄弟、孩子的 cache\_key 没有依赖关系)
7. 无论哪的静态内容更改，有且只有重启后更新，不存在(也不用考虑)嵌套的问题；
8. 静态内容的更新，不影响动态内容的部分(例外见最后)；
9. 例外：动态内容没有指定 cache\_key，只有静态内容同时更新，并且重启，动态内容才会更新。

## 说一说 Cache Key

1\) record 的 cache\_key

2\) helper 方法 cache(name = {}, options = nil, \&block) 这里的 name

3\) 内存数据库 key

不严格区分的话，它们都可以叫做"Cache Key"

但，你可以把它们区分开来：

```ruby
post.cache_key
# => "posts/1-20140921032815201680000”
```

```
<% cache [ 'a_post', post ] do %>
  ... ...
<% end %>
```

```
views/a_post/posts/1-20140921032815201680000/9746fd05c8428f7999681aa804071e9a
(路径    helper方法cache的name部分    静态内容md5)
```

特点：

1 由 record 的"id + updated\_at时间戳"组成，所以 record 更新，cache\_key 会更新 (update\_column等情况不讨论)

2 由我们指定，所以理论上可以随便写。没有嵌套缓存的情况下，一般可以直接使用 1；有嵌套的情况下可以用 touch 更新父亲资源或者使用一个组合，如: cache \[current\_user, post]

3 根据 2 生成 (但不等于 2)，要求唯一 (要不然就没意义了)

2 每次请求都要计算

2 计算之后和 3 对比是否匹配。不匹配则生成新的内容，渲染页面；匹配则返回，渲染页面

2 不匹配，那么意味着之前的内容过期了，过期的内容还是继续存在的数据库里的。(这里的过期不等于被删除)

2 过期的内容可以由我们手动删除，如：Rails.cache.clear；或让数据库自动删除，如 `config.cache_store = :redis_store, 'redis://localhost:6379/5/cache', { expires_in: 90.minutes }` 这里数据最多只能在 redis 里保存 redis 每隔 90 分钟，到期的缓存数据会被删除。(这里的到期等于被删除)

## 几点建议

缓存主要有两种方式过期。 1. 调用 cache(name = {}, options = nil, \&block) 的时候把会引起数据变化的元素都放到 name 里 2. 后续更新一个对象的时候，touch 其关联对象

* 嵌套太深不适合使用缓存(不超过 4 层)
* 涉及太多不同类型的 record 对象时，不推荐使用缓存
* 弱关联(非 has\_many, has\_one, belongs\_to)对象，不适合放在一起做缓存

嵌套太深或 record 对象太多, 或几个对象之间属于弱关联，无论使用哪种缓存过期机制对于维护都是恶梦。
