好用的團隊開發規範,針對現在新版的 Rails 做了一些個人主觀的小修正,筆記下來,順便放一份在 gist 上。
About Ruby Syntax
- 編輯器設定 soft tab (space=2),以 2 格空白符號做為程式內縮距離(不分語言)。
- 函式如果只有一個參數,就不強制打()
- 函式如果有二個以上的參數,通通都要有 ()
- (避免發生奇怪的paser bug跟保持專案一致性)
- 字串限定用雙引號包覆
- 善用
"#{str1} #{str3}"
等字串改寫技巧取代不需要的字串加法。- 非要用加法請用
concat 取代
,避免記憶體浪費(可以用object_id
查看)
- 非要用加法請用
- 變數名稱命名法需使用 my_favorite_game 這種 snake 型命名法,嚴禁駱駝 myFavoriteGame 這種命名方式。在 Ruby 中,使用駱駝法命名的只能是 Class name 或者是 Module name
- 可以用
if
,就避免用unless
,除非unless
較符合原意。- 禁止使用
unless else
或是多重判斷unless a && b
- 禁止使用
- map 要用
{ |c| c.foo }
,不要用do end
。
About Ruby in Rails
- 如果要判斷空字串或空集合等,請用
xxx.blank?
- 不要用
xxx.empty?
,xxx == ""
,xxx.length > 0
- 不要用
- 承上點的相反情形,如果要判斷字串或集合是否有任意成員,請用
xxx.present?
"xxx".present?
#=> true["hi","hello"].present?
#=> true[].present?
#=> false
- 關於 elsif
- 使用elsif前先思考,處理的邏輯是否有關連性,若無請分成多個 if 或 case when 去處理
- 若有相關性,但必須使用到 elsif,思考一下是否有更 magic 且乾淨的方式去處理
About View
- view 只處理「畫面顯示」相關的細節
- 不要在 view 中做任何「拉」資料的動作,至少不應在 view 中做任何 db 操作。(側邊欄的實作例外,因為要上 cache,此時不應該在 application controller 下 query,因為會多出超多無用 query )
- 下拉式選單(select) 的 options 應該是屬於 helper 層級應該要準備的資料,不應該在 view 製作。
- 如果你沒有把握這個頁面只會用到這個id一次,就不要用 id。
- 儘量避免在 view 裡做 if , else 判斷,應用 helper 或 method 包裝邏輯。比如
@post.editable_by?(current_user)
。而非直接在 view 寫 if / else 判斷 current_user 是否存在且是否作者。 - 善用 helper
- h(word) -> plain text
- s(html) -> 消毒 html
- u(url) -> urlencode
truncate(word,:length => length , "...")
-> 斷句- 請勿寫成
truncate(word , 70)
,而要寫成truncate(word , length: 70)
- 請勿寫成
- helper 也要用() 包起來
- 如果有要寫在頁面的 javascript,可使用content_for :page_specific_javascript ,這樣就可以達到在 /body 前執行的效果。
- 當然layout也要記得定義 yield(:page_specific_javascript) 在正確的位置,沒必要的話script盡量放 /body 前。
About Static Files (Javascript/css/image/html…)
- 應該要放在 public 資料夾下,依照 javascripts/stylesheets/images項目分類,html 則依 request url 路徑置放。
- css 用到的圖片應該要放在 stylesheets/image 底下,也就是css所在當前位置的image子資料夾下。
- css 中我們有針對body上兩個指定瀏覽器才有的class類別(ie6 ,ie -> for ie7 and after ),也有針對不同controller 、action上不同的class類別,有需要針對特定版本或特定頁面設計時可多加利用。
About Helper
- 主要是放跟 view 相關的東西
- helper 裡不要放”太多” 純 html 的東西。如果要寫大片的 html,應該在 view 裡面寫 partial。如果真的要放 html,應使用
content_tag
(Rails 5.1 以上請用 tag helper ex:tag.div
) 而非寫 inline html,以免貼 html 因為雙引號問題,造成 syntax error。 - helper 不要放 instance variable,應把 variable 改寫為 parameter 由外部傳入。
- 禁止在 helper 裡使用 yield
- 只要牽扯到圖都應該寫 helper
About Controller
- application controller 每個頁面都會呼叫到,請特別小心使用 db query 。
- 會有三個controller 以上公用的函式 應該要放到 application controller
- 如果是 model 自己的資料轉換 (如 year/month/date 的資料格式轉換),這責任應該在 model,而非 controller
禁用 link_to @resource, form_for @resource , redirect_to @resource 此種 magic method。請拆開來老老實實寫,不要貪圖求快用這種寫法。
- 這種寫法在多個專案內已被證明:
- (1) 當作 STI 時,在 Application 內會大幅爆炸
- (2) resource 的 model 與 controller 同名的時候雖然沒事。但一但要改版拆開名字時,即使用 git grep 檢查關鍵字還是會檢查不乾淨,造成改版後大量爆炸(因為無法用
git grep "resource_path"
)。
- 這種寫法在多個專案內已被證明:
notice_stickie 記得用 () 包起來,但 redirect_to 不需要
controller 裡嚴禁寫 view code
請用善用 before_action 確保主要物件是存在的。
before_action :load_answer, :only => [......]
def load_answer
@answer = Answer.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
About Model
- model 吐出去的東西只能是純天然物質,如 字串、陣列、Hash 等。如果是製作 select option 需要塞字串,請至 helper 加料,嚴禁在 model 內加料。
- many to many 的 named_scope 如果有 order => “xxx DESC” 會造成 join 的 table scan ,解法是拆 query。
About Time 時區的細節
- 在 config/enviroment.rb 裡設定 config.time_zone = ‘Taipei’ 但是資料庫儲存的是 UTC 的時間 如果有需要用 conditions 下 SQL 語法撈資料 請檢查是否必須用 Time.now.utc 避免出錯
學習參考用投影片以及 application
- Rails Best Practice http://www.slideshare.net/ihower/rails-best-practices
- 禁止從 Redmine 學習寫 Rails Code,它的 code 太髒了,會造成 RD 走火入魔。要學習的話應該是 Refactoring Redmine 這本書 http://www.refactoringredmine.com/
- http://jetpackweb.com/blog/2009/10/14/high-quality-ruby-on-rails-example-applications/
- http://github.com/engineyard/rails_dev_directory