Ruby on Rails 實戰聖經

使用 Rails 5.0+ 及 Ruby 2.3+

電子書製作中,歡迎留下 E-mail,有消息將會通知您。若您有任何意見、鼓勵或勘誤,也歡迎來信給我。願意贊助支持的話,这是我的支付宝微信 和乙太幣 ETH 地址
0x232b7245EBE02900c21682be1e6Ad4e839751F6a

錦囊妙計-後端篇

When you choose a language, you’re choosing more than a set of technical trade-offs—you’re choosing a community. - Joshua Bloch

這兩章介紹一些常見的Rails疑難雜症問題,以及常用的RubyGem套件。更多熱門套件可以參考 The Ruby Toolboxawesome-rubyawesome-rails-gem 等介紹。

如何除錯 Debug?

就三個步驟:

  1. Reproduce: 有特定的步驟可以重現這個 bug
  2. Isolate: 找出是哪一段 code 造成這個 bug
  3. Fix: 修好他

詳細可以參考 The Art of Debugging 一文

Debug 方法

  1. 在 template 中使用 <%= debug your_variable %>
  2. 使用 Rails.logger
  3. 使用 web console 發生例外的時候會出現,或是自己放 console 到程式裡面
  4. 使用中斷點 byebug (使用指令 continue 讓中斷繼續)

byebug 詳細用法請參考 https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md

  1. 進一步找 Rails 或其他 gem 的原始碼了解
    • 執行 bundle open the_gem_name 會用預設的編輯器打開,可在 ~/.bash_profile 裡面設定 export EDITOR="subl"
  2. https://github.com/brentd/xray-rails 打開 template 和 partial 的好工具

  3. https://github.com/rails/spring 有時候重開還是沒用沒有載入到修改的設定,可以試試 bin/spring stop

其他參考文章

如何查找 Gem 的原始碼?

除了 Gem 的文件,直接查找 Gem 的原始碼有時候也是除錯或看用法的最好方式:

  • 執行 bundle open GEM_NAME 就會用預設的編輯器打開 gem 的原始碼了。
  • 如果你想看 Rails 的原始碼,由於 Rails 拆分成不同的 gems,所以 bundle open rails 打開來不會看到所有的 Rails 原始碼。建議讀者可以直接 git clone git@github.com:rails/rails.git 一份官方的原始法回去即可。

Rake

Rake 用來編寫任務腳本,讓我們在CLI中可以執行。它的好處在於提供良好的任務編寫結構,並且很方便設定各個任務的相依性,例如執行任務C前,需要先執行任務A、B。在 Rails 之中就內建了許多 rake 指令,除了你已經使用過的 rake db:migrate 之外,你可以輸入 rake -T 看到所有的 rake 指令。

而要在 Rails 環境中撰寫 Rake,請將附檔名為 .rake 的檔案放在 lib/tasks 目錄下即可,例如:

# /lib/tasks/dev.rake
namespace :dev do

  desc "Rebuild system"
  task :rebuild => ["db:drop", "db:setup", :fake]

  task :fake => :environment do
      puts "Create fake data for development"
      u = User.new( :login => "root", :password => "password", :email => "root@example.com", :name => "管理員")
      u.save!
  end
end

透過執行 rake dev:rebuild,就會砍掉重建資料庫,最後執行 rake dev:setup 建立一些假資料作為開發之用。

推薦 https://github.com/stympy/faker 這個 gem 可以產生各種假資料

其他常見的使用情境包括:1. 修正上線的資料,這樣部署到Production後,可以用來執行 2. 建立開發用的假資料 3. 搭配排成工具使用,例如每天凌晨三點寄出通知信、每週一產生報表等等

更多介紹可以參考 http://jasonseifer.com/2010/04/06/rake-tutorial 這篇文章。

分頁

檔案上傳

  • Paperclip 是目前使用上最為方便的檔案上傳 plugin。
  • CarrierWave 寫起來比較繁瑣但設計比較嚴謹

範例 source code

paperclip 如何上傳任意格式的檔案?

假設欄位叫做 attachment 的話,改成以下宣告:

has_attached_file :attachment
do_not_validate_attachment_file_type :attachment

設定檔處理

在整合第三方應用時,第三方的 API Key 和 token 等等,我們不希望 hard-code 在程式碼裡面,一來是因為我們可能不想把這些敏感的 keys commit 進去版本控制系統。二來是因為將來佈署的時候,在 staging 和 production 不同環境下,這些 key 都會不一樣,我們希望容易抽換。

因此,有幾種作法和考量:

使用 YAML 格式作為設定檔放到 config 目錄下

fb_config = YAML.load(File.read("#{Rails.root}/config/facebook.yml"))[Rails.env]fb_config = Rails.application.config_for(:facebook)

要注意

  • YAML 會區分數字和字串,例如 01234 會看成 1234,如果要確保被看成字串,請加上引號,例如"01234"
  • 讀出來的 Hash 是用字串 key,不是 symbol key。例如是 fb_config["app_id"]而不是 fb_config[:app_id]
  • 如果要通吃,可以用symbolize_keys這個方法,例如fb_config = fb_config = Rails.application.config_for(:facebook).symbolize_keys 。這樣用字串或 symbol 都可以。

如果不要 commit,請加進 .gitignore

因為設定檔的東西不同開發者可能不一樣、而且可能包括敏感資料,因此如果不要 commit,就列在 .gitignore 裡面。

並且依照開發者慣例,我們會產生一個 xxx.yml.example 檔案當作設定範例給同事參考。例如: 放 AWS key 的 s3.yml.example、放 email 設定的 email.yml.example

一些 commit 也無妨的情況

但是如果該設定檔的內容機密層級低、專案是放在 private repository 的話(各位的練習作業和期末專案是放在 public repository),而且每個開發者的設定檔都長得一樣,那麼 commit 出去也無妨,大家開發會比較方便。例如config/database.yml 地的資料庫帳號密碼,大家可以講好都設成一樣帳號root、密碼留空即可。

除了寫在 YAML 檔案中,這些 token 也可以寫進config/secret.yml,例如以下的設定,用Rails.application.secrets.batchbook_api_key就可以拿到值了。

development:
  secret_key_base: XXXXXX
  batchbook_api_key: YYYYYYYY

環境變數作法

也有一些人不喜歡用 yaml 載入,而是用環境變數。請參考 The Rubyist’s Guide to Environment Variables 這篇文章的作法。

通常是對 Linux 環境比較熟悉的同學,比較喜歡用這種作法。Heroku 也有專文 The twelve-factor app 推崇這種作法。

ActiveReord: 加強搜尋

  • Ransack可以很快的針對ActiveRecord做出排序和複雜的條件搜尋。不過 ransack 並不太考慮效能問題,特別是文字模糊搜尋,這部份網站長大後會改用全文搜尋引擎,例如 ElasticSearch

ActiveReord: 列表結構(自訂排列順序)

搭配 jQuery UI Sortable 就可以做出拖拉排序,可以參考 Sortable Lists這篇文章。

Model 設計:

UI 設計可用 jQuery UI Sortable:

Example Code: https://github.com/ihower/rails-exercise-ac5/blob/master/app/views/events/index.html.erb

ActiveReord: Self-referential Relationships

1-to-many tree 樹狀結構 (parent and children)

many-to-many

ActiveReord: Tagging 標籤

可以自己寫,也是多對多模型,搭配虛擬屬性(Virtual Attribute)的設計來達到使用者可以輸入任意的 tag name Tag model: name, taggings_count Tagging: tag_id, {target_model}_id

ActiveReord: Soft Deletion 和版本控制,編輯和刪除後還可以留下紀錄和還原,

  • paper_trail 另開一個 versions table 完整紀錄
  • paranoia 加一個欄位標記被刪除。不建議用這種方式,因為會讓資料庫的 unique key 檢查出問題。
  • audited

ActiveReord: 有限狀態機

適合用來設計比較複雜的 model 流程狀態

ActiveReord: 資料表註解

會幫你在model code上面註解加上所有資料表的欄位

根據ActiveRecord的關聯自動產生漂亮的Entity-Relationship Diagrams

API 串接:處理 HTTP

Ruby 內建的 Net::HTTP 設計的不是很好用,因此大多數人改用其他 API 比較好用的函式庫,例如:

範例 Source Code

安裝 gem 'rest-client'

一些 API 資料來源

  • Github API: https://api.github.com/users/ihower
  • 政府開放資料 http://data.gov.tw/
  • g0v 開放資料 http://data.g0v.tw/
  • SheetHub http://sheethub.com
  • 資策會 Social Event Radar http://api.ser.ideas.iii.org.tw/docs/#!/fb_fanpage_search
  • 台北市政府開放資料 http://data.taipei/
  • 臺北市政府 食材登錄平台 https://taipeicity.github.io/foodtracer/
  • 臺北市政府 交通即時資料 開放資料專區 https://taipeicity.github.io/traffic_realtime/

PDF

  • Prawn 可以產生 PDF,支援 Unicode。
  • PDFKit 則是另一個有趣的產生方式,透過 HTML/CSS 轉 PDF。
  • Prince 是一套商用方案,將 HTML/CSS 轉 PDF

CSV

Ruby就有內建這個函式庫了,只需要require "csv"即可使用。

YAML

Rails 的資料庫設定檔 database.yml 是用一種叫 : YAML Ain’t Markup Language 的格式所撰寫,檔案打開來,看起來就像一般的 plain 設定檔,非常容易修改。

YAML 的設計首要目標就是要讓使用者容易看懂,可以和 script 語言搭配良好。用途有 資料序列化 data serialization、設定檔 configuration settings、log files、Internet messaging、filtering 等。網站上已知有支援的 script 語言有 Python,Ruby,Java,PHP,Perl,Javascript 等。

require ‘yaml’

ps2 = YAML.load_file(‘example.yaml’)
ps2.each do |it|
  puts it.inspect
end

JSON

Rails 內建就有 ActiveSupport JSON,用法如下:

ActiveSupport::JSON.encode( [ {:a => 1 , :b => 2 } , "c", "d" ] )
=> "[{\"a\":1,\"b\":2},\"c\",\"d\"]"

ActiveSupport::JSON.decode( "[{\"a\":1,\"b\":2},\"c\",\"d\"]" )
=> [{"a"=>1, "b"=>2}, "c", "d"]

yajl-ruby 則是一套底層用C,比較快很多的 JSON parser,建議可以讓Rails底層改用這套函式庫,請在Gemfile檔案中加入

gem 'yajl-ruby', :require => 'yajl'

XML

Rails 內建使用 Ruby 的 XML 函式庫 Builder

Nokogiri 是一套基於 libxml2 的函式庫,效能較佳。可參考 Getting Started with Nokogiri 一文介紹用法。

如果要替換 Rails 內建的 XML 函式庫,請在Gemfile檔案中加入

gem 'nokogiri'

有些函式庫為了執行效率,底層會改用 C 的函式庫,適合於正式上線環境,缺點是需要編譯,在一些特殊環境可能無法運作,例如最新版的 Nokogiri 就不支援 Windows 了。而純 Ruby 實作的版本就沒有這個問題。

排程工具

如果您有週期性的任務需要執行,除了可以透過Linuxcrontab設定去執行rake腳本。例如輸入crontab -e加入:

0 2 * * * cd /home/your_project/current/ && RAILS_ENV=production /usr/local/bin/rake cron:daily

就是每天凌晨兩點執行rake cron:daily這個任務。

或是你可以安裝whenever這個 gem,就可以用Ruby的語法來定義週期性的任務,可以很方便的設定伺服器上的cron排程。

自動備份

可以搭配 whenever 就可以定期備份了

升級Rails

小版號的升級,通常透過以下步驟即可完成:

  • 修改GemfileRails版本: gem 'rails', '3.1.1'
  • 執行bundle update
  • 執行rake rails:update 會嘗試更新Rails自己產生的檔案,例如config/boot.rb,請一一手動檢查。

升級前,也請參閱官方公告的升級注意事項。

其他

》回到頁首