既然要說 Ruby 那肯定是離不開 Rails 的娄涩,畢竟
Ruby 只是 Ruby on Rails 的一套框架氯哮,才不是什么程序語言呢叁鉴!
話不多說先新建一個(gè) Rails 項(xiàng)目:
$ rails new app --B
默認(rèn)情況下洲劣,Rails 提供了三個(gè)環(huán)境:development碘饼,test 和 production,其定義是在 app/config/environments 目錄下弛说,以后的配置都是要考慮這三個(gè)環(huán)境的(手動(dòng)修改過相關(guān)配置的可能不一定是三個(gè))挽懦。重點(diǎn)要說的是 app/config/secrets.yml 這個(gè)文件
# app/config/secrets.yml
development:
secret_key_base: 5734127d4e3ebf07d9d7af9aed02b869448faf4afefc7bb7abbfdb9979ed92546ee84edbc37e0e50b5469c0d43923faf2d2d9e46d5f5f0d1d997f47b656dbd45
test:
secret_key_base: 35469501039e3c1abc7f4b76d8184df2c6ed0491a6b4f522be84ae5c52d4cf7e5ef31e50f5f063794d076d25e78ce76e8533e72ea20171193c59de861e861b1a
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
其中 production 的值是 <%= ENV["SECRET_KEY_BASE"] %> (至于為什么 yaml 文件中可以使用ERB,可以點(diǎn)這個(gè)鏈接查看原因下面也會(huì)提到一點(diǎn)具體代碼)木人,那么問題就來了信柿,這個(gè) ENV 到底是個(gè)啥子?xùn)|東呢?
ruby-doc 上是這么解釋的:
ENV is a hash-like accessor for environment variables.
由此可知醒第,生產(chǎn)環(huán)境下的這個(gè) secret_key_base 是一個(gè)很 隱私渔嚷? 私密?機(jī)密稠曼? 敏感形病?的數(shù)據(jù),不能讓其出現(xiàn)在代碼倉(cāng)庫之中,而要將其放在環(huán)境變量 ENV 中(很多非 Rails 項(xiàng)目漠吻,更準(zhǔn)確的講是 Rubygem 項(xiàng)目都沒有注意到這個(gè)量瓜,就我個(gè)人而言,即使是測(cè)試環(huán)境下的外部測(cè)試帳號(hào)信息也是敏感數(shù)據(jù))途乃。具體做法 Railscast 上也有一節(jié)是專門講這個(gè)的(不過好像是 revised 的)榔至。
那么,在 Ruby 項(xiàng)目中這又是如何實(shí)現(xiàn)的呢欺劳?
顯然唧取,純 Ruby 項(xiàng)目沒有 Rails 考慮的那么周到,從 Rails 到 Ruby 其感覺就像是一夜回到解放前划提,不過自從有 bundle 工具之后枫弟,起碼可以說回到解放后了。
下面以 JPush API Ruby Client (這是一個(gè) gem 包鹏往,即為 Ruby SDK淡诗,為方便起見,下文統(tǒng)一稱為 SDK)為例來說道說道伊履。
首先細(xì)化一下這個(gè) SDK 的使用場(chǎng)景:有一個(gè)使用 Rails 作為后臺(tái)的項(xiàng)目韩容,現(xiàn)在需要使用極光推送為手機(jī)客戶端提供消息推送服務(wù),那么在服務(wù)端就需要集成 JPush 的 Ruby SDK唐瀑。首先要安裝這個(gè) gem群凶,得益于 bundle 工具,只需要在 Gemfile 里面添加相應(yīng)的配置即可:
# Gemfile
gem 'jpush'
然后運(yùn)行
$ bundle install
DONE哄辣!
JPush SDK 便已經(jīng)成功安裝到 app 項(xiàng)目中请梢。
在 Rails 項(xiàng)目中有三個(gè)環(huán)境,對(duì)于不同的環(huán)境可能需要給 SDK 不同的帳號(hào)信息力穗。比如微信就存在微信公眾平臺(tái)接口測(cè)試帳號(hào)一說毅弧,不過很多其他的服務(wù)(包括極光推送)并不存在測(cè)試帳號(hào)一說。不論如何去做当窗,可以確定的是够坐,處于生產(chǎn)環(huán)境中的 SDK 的敏感信息可以交由 Rails (即 使用這個(gè) SDK 的項(xiàng)目本身)來管理,并不需要 SDK 來做崖面,但是在 SDK 開發(fā)測(cè)試過程中的敏感信息就要 SDK 自己來管理了元咙。
根據(jù)以上的結(jié)論,在 SDK 項(xiàng)目的代碼里面應(yīng)該有一個(gè)下面這樣的類
module JPush
class Client
def initialize(app_key, master_secret)
xxx
end
end
end
來管理賬戶信息嘶朱,這個(gè)類的實(shí)例化蛾坯,留給使用這個(gè) SDK 的開發(fā)者在自己的項(xiàng)目中去做。
在單元測(cè)試中疏遏,需要在 test_helper.rb 中實(shí)例化這個(gè) Client 類,但是帳號(hào)信息哪里來,這是個(gè)問題财异。在這里有幾種方案(偷師 Rails):
- 設(shè)置系統(tǒng)級(jí)環(huán)境變量倘零,然后從 ENV 中讀取
- 將需要的變量寫入一個(gè) yaml 文件,在初始化測(cè)試的時(shí)候?qū)戇M(jìn) ENV 中戳寸,再讀取
等等呈驶,既然可以寫進(jìn) yaml 文件中,Ruby 本身又能方便的處理 yaml疫鹊,那為什么還要寫進(jìn) ENV 里面呢袖瞻。
所以結(jié)論是新建一個(gè) config.yml 將需要填寫的信息模板寫進(jìn)去,比如:
# test/config.yml.example
app_key: APP_KEY
master_secret: MASTER_SECRET
tags:
tag0: TAG_0
tag1: TAG_1
然后在 test_helper.rb 中處理
# test/test_helper.rb
# symbolize_keys 是在其他地方實(shí)現(xiàn)的解析嵌套 Hash 的方法
cnf =
if File.exists? cnf_file = File.expand_path('../config.yml', __FILE__)
require "yaml"
YAML.load_file(cnf_file).symbolize_keys
else
raise 'No Config File Found!!'
end
app_key = cnf[:app_key]
master_secret = cnf[:master_secret]
@@client = JPush::Client.new(app_key, master_secret)
當(dāng)然這里省略了一些細(xì)節(jié)拆吆。需要把 config.yml 加入到 .gitignore 中聋迎,在項(xiàng)目中只能有一個(gè) config.yml.example 文件,這樣的話枣耀,參與開發(fā)的流程就應(yīng)該是
- fork 項(xiàng)目
- $ cp test/config.yml.example test/config.yml
- 編輯 test/config.yml 霉晕,填寫所需的信息
- $ bundle exec rake test
然而,持續(xù)集成那邊 Travis CI build 出錯(cuò)捞奕,原因也很清楚牺堰,可以寫腳本讓其復(fù)制 config.yml 但是無法做到填寫數(shù)據(jù)。各種數(shù)據(jù)都是 example 的數(shù)據(jù)颅围,沒有任何意義伟葫,好在 Travis 可以為其設(shè)置環(huán)境變量,這樣的話院促,只要稍微改一改就可以完成扒俯。因此上面說的那句話
Ruby 本身又能方便的處理 yaml,那為什么還要寫進(jìn) ENV 里面呢
我收回一疯。
# test/config.yml
app_key: <%= APP_KEY %>
master_secret: <%= MASTER_SECRET %>
tags:
tag0: <%= TAG_0 %>
tag1: <%= TAG_1 %>
# test/test_helper.rb
# symbolize_keys 是在其他地方實(shí)現(xiàn)的解析嵌套 Hash 的方法
cnf =
if File.exists? cnf_file = File.expand_path('../config.yml', __FILE__)
require "yaml"
require "erb"
template = File.read(cnf_file)
erb_result = ERB.new(template).result
YAML.load(erb_result).symbolize_keys
else
raise 'No Config File Found!!'
end
這樣的話撼玄,開發(fā)流程其實(shí)并沒有怎么變,只不過多了一個(gè)選擇墩邀,可以選擇編輯 test/config.yml 或者設(shè)置相應(yīng)的環(huán)境變量掌猛,關(guān)于 Tiavis CI 的話,只需添加相應(yīng)的環(huán)境變量眉睹,便能順利的構(gòu)建荔茬。
OVER