鼬~~~哩賀,我是寫程式的山姆老弟,今天是我們的開賽第二天!
不免俗的來看一下,RailsGuides 的 Getting Started with Rails 這篇寫了什麼,我看的文件是 Rails 7 的版本,有一些新的發現,覺得挺不錯的,分享給大家!
在 free-programming-books repository 中,含有大量的免費學習資源
跟大家分享我看到幾個很驚艷的
Ruby one-liners cookbook - Sundeep Agarwal:這本跟 Rails 沒關係,但打開了我的眼界,原來 ruby 還可以這樣玩
顧名思義,這本書就是在講「怎麼用 1 行 ruby 搞定需求」,實在是太多 Magic 了,Bash + Ruby + Regex 可以這麼酷
備註:最前面有 $
符號,表示是在終端機所輸入的指令
# 如何優雅處理 JSON 格式資料?
## jp 的意思是 json parse 的縮寫
## 這行意思是,建立一個叫做 jp 的 bash function
## 這個 function 會對輸入參數執行 JSON.parse 並放在 input 的區域變數裡
## 然後可以針對 input 變數,執行隨後指定的 ruby 程式
## 簡單來說,就是建立一個 bash 捷徑,並利用 ruby 把 JSON 格式的資料,快速結構化取出
## 把下面這行加到 ~/.bashrc 或 ~/.zshrc,方便之後快速使用
$ jp() { ruby -rjson -e 'input = JSON.parse(ARGF.read);'"$@" ; }
## 假設你已經有一堆 json 格式的資料
$ cat sample.json
{
"fruit": "apple",
"blue": ["toy", "flower", "sand stone"],
"light blue": ["flower", "sky", "water"],
"language": {
"natural": ["english", "hindi", "spanish"],
"programming": ["python", "kotlin", "ruby"]
},
"physics": 84
}
## 可以直接用 hash 格式,取出所有資料
$ jp 'input.each {|k,v| puts "#{k}: #{v}"}' sample.json
fruit: apple
blue: ["toy", "flower", "sand stone"]
light blue: ["flower", "sky", "water"]
language: {"natural"=>["english", "hindi", "spanish"], "programming"=>["python", "kotlin", "ruby"]}
physics: 84
## 取出我想要的資料
$ jp 'puts input.dig("language", "programming")' sample.json
python
kotlin
ruby
這只是其中一個範例,讓我體會到,原來可以利用 ruby 的特性跟 bash 結合,做出酷酷的功能
這本書還有很多跟 Regex 相關的範例,但小弟的 Regex 實在是不太行,就不拿出來獻醜了
Ruby Notes for Professionals - Compiled from StackOverflow Documentation (PDF):其實這本書叫做 Ruby on Rails Notes for Professionals,不知道為什麼被縮短成這樣
這本書最後一次更新是 2018 年,有 Rails 5 的內容,還不算太舊,雖然書名是表示寫給專業的 Rails,但我大概看下來,覺得新手也蠻適合看的,從入門到進階的議題都有包含
我挑其中一小段來跟大家分享,我選的這一章是 Rails Best Practice,其中的 Section 6.2: Domain Object (No More Fat Models)
小節,跟我以往用 Rails 的方式不太一樣,先直接上範例
# Bad Practice
# app/models/order.rb
class Order < ActiveRecord::Base
SERVICE_COMMISSION = 0.15
STRIPE_PERCENTAGE_COMMISSION = 0.029
STRIPE_FIXED_COMMISSION = 0.30
...
def commission
amount * SERVICE_COMMISSION - stripe_commission
end
private
def stripe_commission
amount * STRIPE_PERCENTAGE_COMMISSION + STRIPE_FIXED_COMMISSION
end
end
作者認為,Controller 要越簡單越好、比較繁雜的細節要放在 Model,但很多細節都塞在 Model,也會讓 Model 變得太肥,塞太多客製化的細節,就像上面的 Bad Practice 範例一樣,一個訂單的 Model,放了一些針對某服務(這邊的例子是 Stripe 金流服務)的常數、和綁定某服務的計算公式,如果今天需要整合另一個金流服務的話,那 Model 就會越變越大、也不好修改
所以作者建議要導入 Domain Object
的概念,優化成以下這樣
# app/models/order.rb
class Order < ActiveRecord::Base ...
# No reference to commission calculation
# 簡化 Model 內部
end
# lib/commission.rb
class Commission
SERVICE_COMMISSION = 0.15
def self.calculate(payment_method, model)
model.amount * SERVICE_COMMISSION - payment_commission(payment_method, model)
end
private
def self.payment_commission(payment_method, model)
# There are better ways to implement a static registry,
# this is only for illustration purposes. Object.const_get("#{payment_method}Commission").calculate(model)
end
end
# lib/stripe_commission.rb
class StripeCommission
STRIPE_PERCENTAGE_COMMISSION = 0.029
STRIPE_FIXED_COMMISSION = 0.30
def self.calculate(model)
model.amount * STRIPE_PERCENTAGE_COMMISSION + STRIPE_PERCENTAGE_COMMISSION
end
end
# app/controllers/orders_controller.rb
class OrdersController < ApplicationController
def create
@order = Order.new(order_params)
@order.commission = Commission.calculate("Stripe", @order)
...
end
end
從這個範例來看,作者的 Domain Object
的意思是,把一些特殊的商業邏輯,往 lib/
拉,這個概念合理,但我看起來是有點問題的,就是當太多商業邏輯都是這樣拉的話,最後還是會在 lib/
內混在一起,舉例來說,Stripe 金流拉出來放在 lib/
,變成 lib/stripe_commission.rb
;綠界的金流也拉出來 lib/ecpay_commission.rb
,先不說其他金流,如果再拉第三方登入各平台的邏輯進來的話,那 lib/
真的會很熱鬧,所以其實問題還是一樣
我以前使用的習慣跟作者的差不多,只不過不是塞在 lib/
,而是放在 app/services
底下,但概念上還是不同,services 感覺起來會是更大一點的,不知道這樣講有沒有人懂 XD,就是可能一個 service 就等同於串一個 stripe 金流的概念,所以一個 app/services/stripe_service.rb
,裡面可能會有 結帳、開發票、查訂單 等功能,跟 作者的意思不太一樣,就先解釋到這吧,不是這篇重點。
總之,這本書編排方式不錯,每個 Section 的內容安排很精要,不會很多廢話,就算不看文字,直接看 code 也是會懂。
在 Getting Started with Rails 的第五點 - Autoloading,這段是我一直都很好奇,Rails 到底是怎麼做到的,這段講說:只要放在 app/
底下的檔案,都不需要使用 require
去引用其他 ruby 檔案,就可以直接使用,是個很酷的功能!
明天就來研究一下 autoloading 的機制吧,直接幫明天的我省下煩惱 XD
在 **7.5 Deleting an Article 這一節,看到了酷東西,我之前沒用過,從 Turbo 官網的介紹是可以減少 JS 的數量,應該就是不需要每個 action 都要獨立出一個 js 檔案,這樣確實是挺方便的,跟之前看過的 Hotwire 不知道差在哪裡,後面幾天有機會來研究一下
結果 Hotwire 官網就有介紹說,Hotwire 的核心就是用 Turbo XD
Getting Started with Rails
這篇,大致上是讓 Rails 新手對 Model, View, Controller(MVC) 有個基礎的操作概念,以及怎麼讓一個基礎頁面呈現、操作兩個 Model 的 CRUD(Create-Read-Update-Delete),這篇是以部落格當作範例
如果你是 Rails 新手的話,十分建議直接跟著這篇動手做,不要複製貼上,應該會蠻好理解 Rails 的運作,剛開始可能會覺得有點莫名其妙,心裡會感覺:「為什麼這樣就可以動?!」,但這就是 Rails 慣例優於設置的設計哲學所帶來的魔法,在新手階段不需要知道為什麼,只需要知道怎麼做,即使不知道為什麼,也能站在巨人的肩膀上,快速開發出一個像樣的網站
再來是,關於我發現的寶藏,一直以來,我習慣了 Rails 所帶來的方便,這次有機會一探魔法底下的運作原理,實在很興奮,希望能把我理解的,分享給對 Rails 也有興趣的你們,我們明天見~