本課程講解 Rails 中 Assets 管理,異步任務(wù)及郵件發(fā)送,緩存,多語(yǔ)言包,以及如何在服務(wù)器中部署。
在 Rails 上線前,需要做好一些配置工作,并且實(shí)現(xiàn)常見的商用功能,如郵件發(fā)送,語(yǔ)言包,快捷部署等,同時(shí)要了解如何在 linux 服務(wù)器上部署 Rails 程序。
本課時(shí)講解如何管理 Rails 中的 css,js 等靜態(tài)文件。
當(dāng)?shù)谝淮斡?production 運(yùn)行 Rails 時(shí)(rails s -e production),很可能提示找不到資源:
http://wiki.jikexueyuan.com/project/rails-practice/images/chapter_6/1.png" alt="" />
因?yàn)槲覀冞€沒有 編譯 這些靜態(tài)資源,說編譯是因?yàn)?Rails 默認(rèn)使用了 sprockets-rails 這個(gè) gem 來管理 Assets 文件。
Rails 的 Assets 包括已經(jīng)看到的 stylesheets,javascript 和 images,我們還可以增加 fonts。sprockets-rails 提供了幾個(gè)管理這些資源的 Rake 任務(wù)。其中最常用的是 rake assets:precompile。它的含義是,編譯所有在 config.assets.precompile 中定義的資源。
Rails 默認(rèn)加載 app/assets, lib/assets 和 vendor/assets 中的文件到 precompile 路徑中。我們引用這些資源文件的文件,叫 manifest file,可以理解為白名單。這里有兩個(gè)引用命令:
app/assets/styleshetts/application.css
*= require_self
*= require_tree .
這是一種簡(jiǎn)單的引用,require_self 會(huì)先加載自身定義的內(nèi)容,然后加載其他所有目錄下的文件,也就是 require_tree . 中可以找到的文件。但是,我們引用的是 bootstrap 文件,它有變量文件,而 require_tree 命令不一定會(huì)優(yōu)先編譯這個(gè)變量文件,所以會(huì)出現(xiàn):
Less::ParseError: variable @navbar-default-bg is undefined
這樣的錯(cuò)誤。而且當(dāng)項(xiàng)目的 assets 文件越來越多,引用的各種 sass 文件和 less 文件存在互相覆蓋的時(shí)候,require_tree 會(huì)讓這種引用雜亂,且文件臃腫龐大。
這時(shí)我們可以明確引用的文件,比如:
*= require_self [1]
*= require simplex/loader
*= require simplex/bootswatch
*= require bootstrap_and_overrides
如果我們?cè)谠撐募锊粚懫渌?css,可以把 [1] 去掉。
如果我們?cè)?application.css 中寫了一些 css,又 require 了其他文件,如果不使用 require_self,編譯文件中我們寫的 css 不是出現(xiàn)在頂部而可能出現(xiàn)在底部。require_self 會(huì)保持編譯結(jié)果順序和引用順序相同。
這樣運(yùn)行該命令,會(huì)把這些資源編譯到 public/assets 目錄下。那么,其他沒有沒有在此被引入,而也要使用的文件,該如何被編譯呢?
Rails 4 將 assets 的配置文件單獨(dú)放置在 config/initializers/assets.rb 中:
Rails.application.config.assets.precompile += %w( products.js )
Rails.application.config.assets.precompile += %w( cerulean.js cerulean.css )
products.js 文件中定義了兩個(gè)方法,它只在一個(gè)頁(yè)面上使用,就沒必要編譯到整體文件里,只要在需要它的頁(yè)面引用即可:
app/views/products/index.html.erb
<%= javascript_include_tag "products" %>
總結(jié)一下,使用 白名單加載的 assets 文件,可以認(rèn)為是 “編譯+合并” 模式,這適合全局都使用的css 和 js。單獨(dú)寫入 config.assets.precompile 的文件是局部引用。
因?yàn)槲覀儼?bootstrap 中定義的變量放到了 assets 下,所以需要單獨(dú)引用 bootstrap 3 中使用的 Glyphicons 字體:
@font-face {
font-family: 'Glyphicons Halflings';
src: font-url('glyphicons-halflings-regular.eot');
src: font-url('glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
font-url('glyphicons-halflings-regular.woff') format('woff'),
font-url('glyphicons-halflings-regular.ttf') format('truetype'),
font-url('glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}
如果不做任何修改,則不必再次引用,gem 會(huì)自動(dòng)把它們包含進(jìn)來。
如果使用新的字體或圖標(biāo),需要把新字體文件放到 assets/fonts 中,然后定義:
@font-face {
font-family: 'Trajan Pro';
font-style: normal;
src: font-url('trajan_pro/trajan_pro.woff');
src: font-url('trajan_pro/trajan_pro.eot?#iefix') format('embedded-opentype'),
font-url('trajan_pro/trajan_pro.woff') format('woff'),
font-url('trajan_pro/trajan_pro.ttf') format('truetype'),
font-url('trajan_pro/trajan_pro.svg#Regular') format('svg');
font-weight: normal;
font-style: normal;
}
這是一款購(gòu)買的商業(yè)字體,引用的時(shí)候:
<font face="Trajan Pro"><%= product.name %></font>
如果我們不引用編譯的文件,直接使用 application.js 和 application.css 不可以么?這在開發(fā)環(huán)境下自然沒問題,但是在產(chǎn)品環(huán)境下,尤其遇到緩存和 cdn 時(shí),會(huì)造成加載緩慢,無法及時(shí)清理過期時(shí)間的問題。
首先,Rails 默認(rèn)啟用了 assets 的 digest 選項(xiàng),這樣編譯文件的時(shí)候,會(huì)帶有 md5 字符,形象的叫做 指紋。當(dāng)我們修改內(nèi)容之后,其該值會(huì)變動(dòng),生成新的文件名,并且編譯最新的文件。如果我們用 nginx 來作為 web server,可以針對(duì)這種文件設(shè)置緩存,如果使用外部 cdn,可以把最新的文件發(fā)布到 cdn 中(回源模式會(huì)自動(dòng)從服務(wù)器讀取,無需發(fā)布)。
在 nginx 的配置:
location ~ ^/assets/ {
expires 1y;
add_header Cache-Control public;
add_header ETag "";
break;
}
在產(chǎn)品環(huán)境使用 cdn 時(shí),需要更改配置:
config.action_controller.asset_host = "http://cdn.domain.com"
當(dāng)使用 xxx_url 這個(gè) routes helper 時(shí),會(huì)自動(dòng)帶上 cdn 的地址。