4-10 辅助方法controll_name,;SanitizeHelper; 伪元素和scss中的&, @Media; cache介绍。
回顾知识点
1. 在application.html.erb中: <main class="<%= controller.controller_name%>"> 的controller.controller_name是怎么理解?
查api:ActionController::Metal中的实例方法controller_name,
def controller_name
self.class.controller_name #=> 里面调用同名类方法
end
思考:应用模版是根据请求的controller来渲染的,所以这里的controller应该是products.
尝试:在products/index.html.erb中,输出 <h1><%= controller %></h1>得到:实例化的对象#<ProductsController:0x00007fafcc72d070>,所以它的类是ProductsController,然后调用同名类方法,看源码,就是用正则表达式返回string。
def self.controller_name @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore end
解析: ProductsController.name => "ProductsController"
"ProductsController" => 去掉继承的父类字符,还是 "ProductsController"
然后调用sub()把最后的字符串,替换为空。 => "Product"
再用underscore(),在大写字符前加下划线,然后改成小写 => "product"
结论: <main class="<%= controller.controller_name%>">相当于<main class="product">,调用css样式,对应在products.scss
ActionView::Helpers::SanitizeHelper(消毒,净化)
The SanitizeHelper module provides a set of methods for clean text of undesired HTML elements. These helper methods extend Action View making them callable within your template files. 4个方法。
sanitize(html, options = {}) ,可以加白名单
scss:用于编译成html认识的css (详细)
li {
...
}
complied:
li {...}
li::after{...}
::after是psesudo element 一般用于在某个元素后面添加content:"xxx"内容,这里应该是用在li的循环在li之间加一个空行。
The ampersand & in SASS pulls in the parent selector when it compiles to CSS.
什么是css伪元素A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s). For example, ::first-line
can be used to change the font of the first line of a paragraph
/* The first line of every <p> element. */
p::first-line { color: blue; text-transform: uppercase; }
Responsive Web Design - Media Queries
Media query is a CSS technique introduced in CSS3.
It uses the @media
rule to include a block of CSS properties only if a certain condition is true.
Desktop
Phone
勘误《Rails5敏捷开发》:cache P115 缓存局部结果
缺少一段翻译,和关键的一行代码:5.1版原文如下:
⚠️: 这篇博客有详细的案例讲解HTTP cache, fragment cache:
rails默认提供fragment caching。
action caching和page caching需要手动设置:
增加2个gem:actionpack-page_caching和actionpack-action_caching 具体做法需要看文档的连接。
默认情况下,缓存只在生产环境启动,如果想在本地启动缓存,需要:
在config/environments/*.rb中一般是developemnt.rb中:
config.action_controller.enable_fragment_cache_logging = true
如代码所写,缓存只影响action controller,对底层缓存无影响。
片段缓存:
首次访问这个页面时,Rails会创建 一个时间戳(对象的id加updated_at属性),如果updated_at变化了则生成新的键然后写入一个新的缓存。
cache_if/cache_unless方法可以用于特定的条件。
示例:集合缓存,一次性缓存,速度更快。
<%= render partial:'products/product', collection:@products, cache: true %>
示例:片段缓存,
<% @products.each do |product| %>
rails dev:cache 在开发/测试环境打开/关闭缓存
在关联的模型上,如果视图有嵌套,在belongs_to 后加,touch:true,同步判断缓存是否失效。
有时,可能想把缓存的片段嵌套在其他缓存的片段里。这叫俄罗斯套娃缓存(Russian doll caching)。 俄罗斯套娃缓存的优点是,更新单个商品后,重新生成外层片段时,其他内存片段可以复用。
如果缓存的文件对应的记录的 updated_at 属性值变了,缓存的文件失效。但是,内层嵌套的片段不失效。
对下面的视图来说:
而它渲染这个视图:
如果game的任何一个属性变了,updated_at 的值会设为当前时间,因此缓存失效。然而,project对象的 updated_at 属性不变,因此它的缓存不失效,从而导致应用伺服过期的数据。为了解决这个问题,可以使用 touch 方法把模型绑在一起:
class Product < ApplicationRecord has_many :games
end
class Game < ApplicationRecord
belongs_to :product, touch: true
end
这样就同步失效了。目的是让
管理依赖:有时候对需要处理自定义的helper methods,要自定义缓存依赖.
比如自定义的集合:
render @project.documents.where(published: true)
需要改为标准格式:
render partial: "documents/document", collection: @project.documents
.where(published: true), cache:true
Explicit dependency
External dependency
这两个没有弄明白。http://guides.rubyonrails.org/caching_with_rails.html#shared-partial-caching
底层缓存:
缓存特定的值或者query结果。使用Rails.cache.fetch方法 ,详细用法看api.
ActiveSupport::Cache::Store可以储存任何可串联的Ruby对象。
基本的缓存方法:
fetch
, write
, read
, exist?
, and delete
keys会被转化为string.
cache = ActiveSupport::Cache::MemoryStore.new
cache.write("city", "Duckburgh")
cache.read("city") #=> "Duckburgh"
fetch(name, options = nil)
使用给定的key从缓存取数据。如果有对应的数据,返回这个数据。
如果没有对应的数据,返回nil。
如果一个block被传入, key先在缓存中找对应数据,如果找不到,则把block中的数据作为这个key的数据写入缓存,并返回block中的数据。
option选择有多个,如expires_in: 12.hours 在12小时后缓存到期. namespace则用于创建命名空间防止与其他应用共用一个缓存存储器。
下面是个Product模型,有个实例方法,在竞争网站查找某个商品的价格。
SQL缓存
Rails提供的功能,如果在同一请求中遇到相同的查询结果,rails会使用缓存的结果。⚠️的是SQL缓存机制只在一个动作内有效,如果这个动作结束,缓存也就销毁了。如果想持久储存查询结果,可以使用👆讲的底层缓存。
缓存存储器
ActiveSupport::Cache::Store这是基础。
ActiveSupport::Cache::MemCacheStore < ActiveSupport::Cache::Store
在生产环境的网站目前流行使用的缓存存储器。初始化使用的时候,需要指定服务器的地址(具体见rails guide.) fetch和write有额外的option。
需要在config/environments/production.rb中:
config.cache_store = :mem_cache_stor
这个存储器可以和自动到期缓存良好的一起运行。
ActiveSupport::Cache::FileStore 缓存使用文件系统存储缓存条目:
config.cache_store = :file_store, "/path/to/cache/directory"
缓存量会定期增长,需要自己定期清理旧缓存条目。
pasting
ActiveSupport::Cache::MemoryStore 这个是新建rails的默认配置
rails5.2新功能
ActiveSupport::Cache::RedisCacheStore (点击看guide)
Redis cache store利用Redis support当它达到最大memory时会自动驱逐(回收)eviction。行为类似于Memcached cache server。
部署⚠️: Redis不会默认到期expire keys。留心使用专门的Redis cache server。不要用不稳定的缓存数据填满你的persistent-redis server!具体的见https://redis.io/topics/lru-cache
步骤:
1。gem
'redis'
配合使用gem 'hiredis'来加速hiredis连接库,Redis会自动请求/使用hiredis无需配置。
2. 加上配置config/environments/*.rb:
config.cache_store = :redis_cache_store, {url: ENV['REDIS_URL']}
附加:生产模式下的配置样例:
3个提示⚠️:
1. 设置cache read 和 write timeouts相对低一点,默认是1秒。可以设置更低
2. 默认设置是cache store不会再连接redis,如果在一次request后连接失败。
3. cache read和write不会raise exceptions;只会返回nil。为了判断出是否缓存出现意外,你可以自定义一个error_handler来报告你出现意外的信息。 包括开始的mehtod,returning和exception
Cache Keys
可以是任何对象。hash, array格式也行。
ActionController::ConditionalGet
get请求内传递了HTTP_IF_NONE_MATCH和HTTP_IF_MODIFIED_SINCE,服务器看这两个的值和服务器中的值是否一样。一样的话就证明上次返回的结果和本次请求的匹配。于是只返回一个空的响应,目的是节省资源。
HTTP_IF_NONE_MATCH:内容标志符etag
HTTP_IF_MODIFIED_SINCE:updated_at时间戳。
如一样,则返回空 -- 条件get请求
class ProductsController < ApplicationController
简单写法fresh_when last_modified: @company.updated_at
还可以传入模型,rails自动使用updated_at, cache_key设定last_modified和etag.
if stale?(@product)
也可以使用集合@products
fresh_when etag: @products
使用http_cache_forever(public: true) 可以永久缓存页面,不会过期。