🔁 ทวนก่อนเริ่ม (จากบทเรียน 90)
- Ruby = ภาษาโปรแกรม (เหมือน Go) · Rails = framework ที่เขียนด้วย Ruby (ร้านแฟรนไชส์ที่ได้ครัวครบชุด)
- แอปในสไลด์คือบล็อกชื่อ
wongnok_blog· ของหลักคือบทความ ภาษาอังกฤษเรียกว่า post - gem = อุปกรณ์สำเร็จรูปที่ซื้อมาใช้ในครัว · Rails เองก็เป็น gem ตัวหนึ่ง
- บทนี้ยังไม่มี Rails — เราจะจำลองบทความหนึ่งชิ้นด้วยตัวแปรธรรมดา ๆ (
titleชื่อบทความ ·authorคนเขียน ·viewsยอดอ่าน)
🧰 เครื่องที่ใช้ตรวจ: Ruby 4.0.9 · Rails 8.1.4 · irb 1.18.0 · Go 1.26.5 · สไลด์ใช้ Ruby 4.0.6 · Rails 8.1.3 — เลขท้ายต่างกันเป็นแค่รุ่นแก้บั๊ก ไม่มีผลกับบทนี้ · ทุกผลรันในบทนี้ก็อปมาจากเครื่องจริง
1 · terminal กับ mise — เช็คว่ามี Ruby รุ่นไหน
terminal คือหน้าต่างที่พิมพ์คำสั่งเป็นตัวหนังสือ — ตัวเดียวกับที่คุณใช้พิมพ์ go run main.go ตอนเรียน Go
บรรทัดที่ขึ้นต้นด้วย $ ในบทนี้คือคำสั่งที่พิมพ์ใน terminal (ไม่ต้องพิมพ์ตัว $)
ปัญหาแรกของ Ruby คือ เครื่องเดียวมักมีหลายรุ่น เช่น Mac แถม Ruby รุ่นเก่ามาก (2.6) ติดเครื่องมาให้แล้ว แต่คอร์สนี้ใช้รุ่น 4 ถ้าเรียกผิดตัว โค้ดของคอร์สจะพังแบบงง ๆ
mise (อ่านว่า "มีซ") คือโปรแกรมที่ เก็บโปรแกรมไว้หลายรุ่น แล้วเลือกให้ว่าตอนนี้จะใช้รุ่นไหน สไลด์หน้า 14 ใช้มันติดตั้ง Ruby รุ่น 4 แล้วค่อยติดตั้ง Rails ต่อ
mise เหมือนไขควงด้ามเดียวที่มีหัวหลายขนาดในกล่อง ·
Ruby 2.6 กับ Ruby 4.0.9 คือหัวคนละขนาด ·
ไฟล์ mise.toml ที่สไลด์โชว์คือป้ายที่แปะไว้กับโปรเจกต์ว่า "งานนี้ใช้หัวเบอร์ 4.0.6 นะ"
ใครในทีมหยิบโปรเจกต์ไปทำก็ได้หัวเบอร์เดียวกัน
ที่ไม่เหมือนกัน: ไขควงจริงคุณต้องเปลี่ยนหัวเองด้วยมือ ·
mise เปลี่ยนให้เองอัตโนมัติ — แต่ต้องตั้งค่าให้ terminal "ปลุก" mise ขึ้นมาก่อนหนึ่งครั้ง
(คู่มือติดตั้งของ Rails ให้เพิ่มบรรทัด mise activate ลงไฟล์ ~/.zshrc
— ไฟล์ตั้งค่าที่ terminal ของ Mac อ่านทุกครั้งที่เปิดหน้าต่างใหม่)
ถ้าข้ามขั้นนี้ เครื่องจะหยิบ Ruby 2.6 ของ Mac มาใช้แทน
ใน Go คุณไม่ค่อยเจอเรื่องนี้ เพราะติดตั้ง Go ตัวเดียวแล้วใช้ยาวได้ · ใน Ruby การมีตัวเลือกรุ่นเป็นเรื่องปกติของทุกทีม
คำสั่งในสไลด์ (ไม่ต้องรันซ้ำถ้าเครื่องคุณติดตั้งไว้แล้ว):
$ mise use -g ruby@4 # ติดตั้ง Ruby รุ่น 4 ตัวล่าสุด แล้วตั้งให้ใช้เป็นค่าเริ่มต้นทั้งเครื่อง
$ gem install rails # ติดตั้ง gem ชื่อ rails ลงใน Ruby ตัวนั้น
mise use= "ใช้รุ่นนี้" (ยังไม่มีในเครื่องก็โหลดมาให้)-g= ทั้งเครื่อง (global) ไม่ใช่เฉพาะโฟลเดอร์นี้ruby@4= Ruby รุ่น 4 ตัวไหนก็ได้ เอาตัวล่าสุด — สไลด์ได้ 4.0.6 · วันที่ผมตรวจได้ 4.0.9gem install rails= ซื้อ "อุปกรณ์สำเร็จรูป" ชื่อ rails มาไว้ในครัว (gem คืออุปกรณ์สำเร็จรูปจากบทเรียน 90) · คล้ายgo installที่ดึงเครื่องมือของคนอื่นมาลงเครื่อง
ที่ต้องรันเป็นคือคำสั่ง อ่านอย่างเดียว ที่แค่ถามว่ามีรุ่นไหน — ผลรันจริง:
$ ruby -v
ruby 4.0.9 (2026-10-23 revision 3e93b23afc) +PRISM [arm64-darwin25]
$ rails -v
Rails 8.1.4
$ mise --version
2026.8.1 macos-arm64 (2026-08-03)
-v ย่อมาจาก version · ขอแค่บรรทัดแรกขึ้นต้นว่า ruby 4. ก็พร้อมเรียนแล้ว ·
วันที่และรหัสในวงเล็บของเครื่องคุณจะต่างจากนี้ ไม่เป็นไร ·
mise --version อาจมีบรรทัด mise WARN บอกว่ามีรุ่นใหม่ต่อท้าย — ไม่ต้องสนใจ
⚠️ ถ้า ruby -v ขึ้นว่า ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin26]
(ผลจริงของ Ruby ที่ติดมากับ Mac) แปลว่า terminal ยังไม่ได้ปลุก mise —
กลับไปทำขั้น mise activate ในคู่มือติดตั้ง แล้วปิด-เปิด terminal ใหม่
- version manager
- โปรแกรมเก็บภาษาหลายรุ่นแล้วสลับให้ (mise เป็นตัวหนึ่ง · ตัวอื่นที่อาจได้ยินคือ rbenv, nvm) · ถาม senior ได้ว่า "ทีมนี้ตรึงรุ่น Ruby ไว้ที่ไฟล์ไหน"
- gem install
- คำสั่งติดตั้ง gem หนึ่งตัวลงเครื่อง · ในโปรเจกต์ Rails จริงจะจดรายการ gem ไว้ในไฟล์
Gemfileแทน (บทเรียน 98) · พิมพ์บอก AI ได้ว่า "ruby -v shows 2.6 but I installed Ruby 4 with mise, what did I miss?"
2 · irb — กระดาษทดเลขของ Ruby
ตอนเรียน Go ถ้าอยากลองอะไรนิดเดียว ต้องสร้างไฟล์ มี package main มี func main() แล้วค่อย go run
Ruby มีทางลัด: พิมพ์ irb ใน terminal แล้วพิมพ์โค้ดได้ทีละบรรทัด กด Enter เห็นผลทันที
irb ติดมากับ Ruby ไม่ต้องติดตั้งเพิ่ม
เขียนไฟล์ .rb แล้วรัน = เขียนรายงานส่งครู ต้องเรียบร้อย มีหัวมีท้าย ·
irb = กระดาษทดเลข ขีดเขียนลองอะไรก็ได้ ผิดก็เขียนบรรทัดใหม่
ที่ไม่เหมือนกัน: กระดาษทดยังเก็บไว้ดูทีหลังได้ ·
พอพิมพ์ exit ออกจาก irb ทุกอย่างที่พิมพ์ไว้หายหมด —
โค้ดที่อยากเก็บต้องก็อปไปใส่ไฟล์ .rb เอง
ลองเลย — นี่คือหน้าจอจริงหลังพิมพ์ irb (ตัดข้อความต้อนรับตอนเปิดออก):
irb(main):001> 1 + 2
=> 3
irb(main):002> title = "Hello Rails"
=> "Hello Rails"
irb(main):003> title
=> "Hello Rails"
irb(main):004> exit
irb(main):001>คือที่ให้พิมพ์ · เลข 001, 002 คือบรรทัดที่เท่าไหร่ · คุณพิมพ์แค่ส่วนหลัง>· คำว่าmainในวงเล็บแค่บอกว่ากำลังพิมพ์อยู่ "ชั้นนอกสุด" ไม่ต้องสนใจ=> 3คือผลของบรรทัดนั้น irb โชว์ให้เองทุกบรรทัด ไม่ต้องสั่งพิมพ์title = "Hello Rails"คือการสร้างตัวแปรชื่อ title · พิมพ์titleเฉย ๆ = ขอดูค่าข้างใน (เรื่องตัวแปรอยู่หัวข้อถัดไป)exit= ออกจาก irb กลับไป terminal ปกติ
ในบทเรียนและสไลด์ คุณจะเห็นคอมเมนต์ # => "HELLO RAILS" ต่อท้ายโค้ด —
แปลว่า "บรรทัดนี้ได้ผลเป็น…" คือการก็อปผลจาก irb มาเขียนไว้นั่นเอง ·
(# ใน Ruby คือคอมเมนต์ เหมือน // ใน Go)
- irb / REPL
- irb ย่อจาก Interactive Ruby · คนทั่วไปเรียกเครื่องมือแบบนี้ว่า REPL (อ่าน → รัน → พิมพ์ผล → วนใหม่) · พิมพ์บอก AI ได้ว่า "give me a one-liner I can paste into irb to try this"
- return value
- ค่าที่บรรทัดหนึ่งได้ออกมา · ใน Ruby ทุกบรรทัดมีผลเสมอ irb เลยโชว์
=>ได้ทุกบรรทัด · เจอ# => trueในเอกสาร อ่านว่า "บรรทัดนี้ได้ true"
3 · ตัวแปร — ตั้งชื่อแล้วใส่ค่า จบ
ตัวแปรคือชื่อที่เราตั้งให้ค่าหนึ่ง จะได้เรียกใช้ทีหลังได้ ·
ใน Ruby แค่เขียน ชื่อ = ค่า ก็สร้างตัวแปรเสร็จ ไม่มีคำว่า var ไม่มี := ไม่ต้องบอกชนิด
Go — ต้องประกาศ
var title string = "Hello Rails"
author := "Nan" // := เดาชนิดให้
views := 42
Ruby — ให้ค่าครั้งแรก = สร้างเลย
title = "Hello Rails"
author = "Nan"
views = 42
(กล่องซ้ายสีแดงไม่ได้แปลว่า Go ผิด แค่ใช้แยกฝั่งให้ดูง่าย) ·
เว้นวรรคหน้า = ให้ตรงกันเป็นแค่ความสวย ไม่มีผลอะไร ·
นี่คือบทความจำลองของเรา: ชื่อเรื่อง คนเขียน และยอดอ่าน
ตัวแปร Ruby เหมือนสติกเกอร์เขียนชื่อแปะบนกล่อง · title = "Hello Rails" คือ
"แปะสติกเกอร์ title ไว้บนกล่องที่มีข้อความ Hello Rails" · ไม่ต้องไปขอจองสติกเกอร์ก่อน หยิบมาแปะได้เลย
· ใน Go ต้องไปลงชื่อจองก่อนว่า "ช่องนี้ของฉัน ใส่ได้เฉพาะ string"
ที่ไม่เหมือนกัน: ในออฟฟิศถ้าใครเขียนชื่อผิด เพื่อนจะทักว่า "นี่ของใคร" · Ruby ไม่ทัก — เขียนชื่อสะกดผิดตอนให้ค่า มันคิดว่าคุณตั้งใจแปะสติกเกอร์ใบใหม่ (ดูข้างล่าง)
ราคาของความสบายนี้: ลองพิมพ์ชื่อผิดตอนให้ค่า (veiws แทน views) แล้วเทียบสองภาษา — ผลรันจริง:
Go — build ไม่ผ่าน
views := 1
veiws = views + 1
// ./main.go:7:2: undefined: veiws
(โชว์แค่ส่วนใน func main() · เลขบรรทัดนับจากไฟล์เต็ม)
Ruby — รันผ่าน ไม่บ่นสักคำ
views = 1
veiws = views + 1
puts views
# พิมพ์ 1 ออกมา · ไม่มี error
Go รู้ว่า = คือ "เปลี่ยนค่าตัวแปรที่มีอยู่แล้ว" จึงฟ้องว่าไม่มีตัวชื่อ veiws ·
Ruby ใช้ = ทั้งสร้างและเปลี่ยน เลยแยกไม่ออกว่าคุณพิมพ์ผิด ·
(puts = พิมพ์ค่าออกจอแล้วขึ้นบรรทัดใหม่ เหมือน fmt.Println)
ข่าวดีคือถ้าพิมพ์ผิดตอนอ่านค่า Ruby ฟ้องตอนรันและเดาให้ด้วย · ไฟล์นี้สร้าง title แล้วตั้งใจเรียกผิดเป็น titel:
# typo2.rb
title = "Hello Rails"
puts titel
ผลรันจริง (ตัดบรรทัดที่วาดลูกศรชี้ตำแหน่งออก):
typo2.rb:3:in '<main>': undefined local variable or method 'titel' for main (NameError)
Did you mean? title
อ่านว่า "ไฟล์ typo2.rb บรรทัด 3 ไม่รู้จักชื่อ titel · หมายถึง title หรือเปล่า" ·
(บรรทัดแรกที่เป็นคอมเมนต์ชื่อไฟล์ก็นับเป็นบรรทัดด้วย) ·
'<main>' กับ for main แปลว่าโค้ดอยู่ชั้นนอกสุดของไฟล์ ไม่ต้องสนใจ ·
(คำว่า method ใน error คือ "คำสั่ง" — เจอในหัวข้อ 4)
- local variable
- ตัวแปรชื่อขึ้นต้นตัวเล็ก เกิดขึ้นตอนให้ค่าครั้งแรก · พิมพ์บอก AI ได้ว่า "check this Ruby file for misspelled variable names — Ruby won't error on assignment"
- dynamic typing
- ตัวแปรไม่ผูกกับชนิดข้อมูล วันนี้ใส่ตัวเลข พรุ่งนี้ใส่ข้อความก็ได้ · ตรงข้ามกับ Go · ถาม senior ได้ว่า "ทีมใช้อะไรช่วยจับ type ผิดใน Ruby ไหม"
- NameError
- error ตอนรันเมื่อเรียกชื่อที่ Ruby ไม่รู้จัก · ดูบรรทัด
Did you mean?ก่อนเสมอ ส่วนใหญ่เป็นแค่สะกดผิด
ค่าคงที่ — ขึ้นต้นตัวใหญ่
ค่าคงที่คือค่าที่ตั้งครั้งเดียวแล้วไม่ควรเปลี่ยน เช่นชื่อเว็บ ·
Go ใช้คำว่า const นำหน้า · Ruby ไม่มีคำนี้ แต่ดูตัวอักษรตัวแรกของชื่อแทน:
ขึ้นต้นตัวเล็ก = ตัวแปร · ขึ้นต้นตัวใหญ่ = ค่าคงที่ (ปกติเขียนตัวใหญ่ทั้งคำ)
Go — มีคำว่า const
const BlogName = "wongnok_blog"
Ruby — แค่ขึ้นต้นตัวใหญ่
BLOG_NAME = "wongnok_blog"
แล้วถ้าดื้อ เปลี่ยนค่าคงที่ทีหลังล่ะ? ลองเดาก่อนกดเฉลย:
# const.rb
BLOG_NAME = "wongnok_blog"
puts BLOG_NAME
BLOG_NAME = "my_blog"
puts BLOG_NAME
รัน ruby const.rb แล้วจะ (ก) หยุดด้วย error · (ข) เตือนแล้วพิมพ์ my_blog · หรือ (ค) เงียบแล้วพิมพ์ wongnok_blog สองครั้ง?
ได้ (ข) — ผลรันจริงใน terminal:
$ ruby const.rb
wongnok_blog
const.rb:4: warning: already initialized constant BLOG_NAME
const.rb:2: warning: previous definition of BLOG_NAME was here
my_blog
Ruby ยอมเปลี่ยนให้ แค่เตือนสองบรรทัด: "บรรทัด 4 ตั้งค่า BLOG_NAME ซ้ำ" และ "ตั้งครั้งแรกที่บรรทัด 2" (บรรทัด 1 คือคอมเมนต์ชื่อไฟล์) ·
ส่วน Go ถ้าเขียน BlogName = "my_blog" ต่อจาก const จะ build ไม่ผ่าน — ผลจริง:
cannot assign to BlogName (neither addressable nor a map index expression) (แปลว่า "ค่านี้เปลี่ยนไม่ได้")
(ถ้าส่งผลไปเก็บในไฟล์แทนการดูบนจอ ลำดับบรรทัดเตือนอาจขึ้นก่อน เพราะคำเตือนกับผลปกติออกคนละช่อง — ไม่ต้องตกใจ)
ตัวแปรคือสติกเกอร์ชื่อที่ลอกไปแปะกล่องใหม่ได้ทุกวัน (ภาพจากข้างบน) · ค่าคงที่คือป้ายชื่อร้านที่ติดหน้าร้าน ตั้งใจให้อยู่อย่างนั้นตลอด · ใน Go ป้ายชื่อร้านถูกเชื่อมติดผนัง ถอดไม่ได้เลย
ที่ไม่เหมือนกัน: ป้ายชื่อร้านจริงต้องจ้างช่างมาถอด · ใน Ruby ป้ายแค่แปะสก็อตเทป ใครจะเปลี่ยนก็ทำได้ทันที แค่ Ruby ตะโกนเตือนหนึ่งที (warning) แล้วยอมให้เปลี่ยน
กติกาตั้งชื่อ ที่สไลด์หน้า 15 ย้ำ:
ตัวแปรใช้ snake_case (ตัวเล็กหมด คั่นคำด้วย _ เช่น post_title) ·
ชื่อ class ใช้ PascalCase (ตัวใหญ่ต้นทุกคำ เช่น BlogPost)
class คือแม่พิมพ์ของข้อมูล คล้าย struct ใน Go (เจอละเอียดในบทเรียน 95) · ชื่อ class ขึ้นต้นตัวใหญ่ เพราะใน Ruby มันก็นับเป็นค่าคงที่ตัวหนึ่ง · ระวังสับสนกับ Go: Go ใช้ตัวใหญ่-เล็กบอกว่าแพ็กเกจอื่นเรียกใช้ได้ไหม (export) ส่วน Ruby ใช้บอกว่าเป็นค่าคงที่หรือไม่
ใน Rails กติกานี้สำคัญมาก — เหมือนร้านแฟรนไชส์ที่ทุกสาขาวางของตำแหน่งเดียวกัน Rails เดาว่าของอยู่ไฟล์ไหนจากชื่อ ตั้งชื่อผิดแบบ = หาของไม่เจอ (ละเอียดในบทเรียน 99)
- constant
- ชื่อขึ้นต้นตัวใหญ่ · เปลี่ยนค่าได้แต่ได้
warning: already initialized constant· เห็นคำเตือนนี้ในงานจริง = มีคนตั้งค่าซ้ำโดยไม่ตั้งใจ ควรแก้ · พิมพ์บอก AI ได้ว่า "why does Ruby only warn when I reassign a constant?" - snake_case / PascalCase
post_titleสำหรับตัวแปร ·BlogPostสำหรับ class · ใน Rails ตั้งผิดแล้วหาไฟล์ไม่เจอ ไม่ใช่แค่ไม่สวย · ถาม senior ได้ว่า "ใน Rails ชื่อ class กับชื่อไฟล์ต้องตรงกันแบบไหน"
4 · ทุกอย่างเป็น object — ทุกค่ามีคำสั่งติดตัว
ใน Go ค่าอย่าง "Hello Rails" หรือ 42 เป็นค่าเปล่า ๆ ทำอะไรเองไม่ได้ ·
อยากรู้ความยาวต้องส่งเข้าฟังก์ชัน len(title) · อยากได้ตัวใหญ่ต้องไปยืม strings.ToUpper(title)
ใน Ruby ทุกค่าเป็น object แปลว่าทุกค่ามีคำสั่งของตัวเองติดมาด้วย — คำสั่งพวกนี้เรียกว่า method · เรียกใช้ด้วยการเขียนจุดต่อท้ายค่า แล้วตามด้วยชื่อ method
ใน Ruby ทุกของในบ้านมาพร้อมคู่มือการใช้ติดตัว · หม้อหุงข้าวมีปุ่ม "หุง" · ทีวีมีปุ่ม "เปิด" ·
title.upcase คือ "หยิบ title ขึ้นมา แล้วกดปุ่ม upcase ของมัน" ·
ใน Go ของในบ้านเป็นของเปล่า อยากทำอะไรต้องไปหยิบเครื่องมือจากลิ้นชักมาทำกับมัน (strings.ToUpper(title))
ที่ไม่เหมือนกัน: ของจริงคุณมองเห็นปุ่มทั้งหมดก่อนกด ·
Ruby ปล่อยให้คุณเขียนกดปุ่มที่ไม่มีได้ แล้วค่อยพังตอนรันถึงบรรทัดนั้น ·
และของคนละชนิดมีปุ่มไม่เหมือนกัน — ตัวเลขไม่มีปุ่ม upcase
เทียบงานเดียวกันสองภาษา — ผลรันจริงทั้งคู่:
Go — ส่งค่าเข้าฟังก์ชัน
title := "Hello Rails"
fmt.Println(len(title)) // 11
fmt.Println(strings.ToUpper(title)) // HELLO RAILS
fmt.Println(42%2 == 0) // true
Ruby (irb) — กดปุ่มบนตัวค่าเอง
irb(main):001> title = "Hello Rails"
=> "Hello Rails"
irb(main):002> title.length
=> 11
irb(main):003> title.upcase
=> "HELLO RAILS"
irb(main):004> 42.even?
=> true
irb(main):005> 7.even?
=> false
title.length— จุดแปลว่า "ของชิ้นนี้ ทำคำสั่งนี้หน่อย" ·length= นับจำนวนตัวอักษรtitle.upcase— ได้ข้อความชุดใหม่ที่เป็นตัวใหญ่ ·titleตัวเดิมยังเหมือนเดิม42.even?— ถามตัวเลข 42 ว่า "เป็นเลขคู่ไหม" · เครื่องหมาย?เป็นส่วนหนึ่งของชื่อ method ไม่ใช่สัญลักษณ์พิเศษ · ธรรมเนียมของ Ruby คือ method ที่ตอบ ใช่/ไม่ใช่ จะลงท้ายด้วย?(ละเอียดในบทเรียน 93)
ใน Go ลองเขียนแบบเดียวกันกับตัวเลขดู: views := 42 แล้ว fmt.Println(views.Even()) — build ไม่ผ่าน (ผลจริง):
views.Even undefined (type int has no field or method Even)
แปลว่า "int ไม่มีคำสั่งชื่อ Even" · ชนิดพื้นฐานของ Go อย่าง int กับ string ไม่มี method ติดตัว
ขนาด nil (ค่าพิเศษที่แปลว่า "ไม่มีค่า" — เจอในหัวข้อ 5) กับ true ก็เป็น object · ถามได้ด้วย .class ว่า "เป็นของชนิดไหน" — ผลรันจริง:
irb(main):001> 42.class
=> Integer
irb(main):002> "hello".class
=> String
irb(main):003> nil.class
=> NilClass
irb(main):004> true.class
=> TrueClass
Integer = จำนวนเต็ม · String = ข้อความ · NilClass = ชนิดของ nil · TrueClass = ชนิดของ true ·
ทุกตัวตอบได้ เพราะทุกตัวเป็น object
ถ้าเรียก method ที่ของชนิดนั้นไม่มี จะพังตอนรัน — ผลรันจริง (ตัดบรรทัดชี้ตำแหน่งออก):
# nomethod.rb
views = 42
puts views.upcase
# nomethod.rb:3:in '<main>': undefined method 'upcase' for an instance of Integer (NoMethodError)
อ่านท่อน for an instance of Integer ("กับของชิ้นหนึ่งที่เป็นชนิด Integer") ก่อนเสมอ — มันบอกว่า "ของในมือคุณตอนนี้คือตัวเลข" ซึ่งไม่มีปุ่ม upcase
ต่อจุดเป็นทอด ๆ (chain)
ผลของ method ก็เป็น object อีกตัว จึงต่อจุดไปได้เรื่อย ๆ อ่านจากซ้ายไปขวา · ดูทีละขั้น — ผลรันจริง:
irb(main):001> " hello rails ".strip
=> "hello rails"
irb(main):002> " hello rails ".strip.upcase
=> "HELLO RAILS"
irb(main):003> " hello rails ".strip.upcase.length
=> 11
.strip— ตัดช่องว่างหัวท้ายทิ้ง ได้"hello rails".upcase— เอาผลขั้น 1 มาทำตัวใหญ่ ได้"HELLO RAILS".length— เอาผลขั้น 2 มานับ ได้11
ใน Go งานเดียวกันต้องซ้อนฟังก์ชันแล้วอ่านจากในออกนอก: len(strings.ToUpper(strings.TrimSpace(s))) ·
ท่า chain นี้คุณจะเห็นใน Rails บ่อยมาก
ตัวอย่างจากสไลด์หน้า 16: Post.published.recent.limit(10) ·
วันนี้ไม่ต้องเข้าใจว่าข้างในทำงานยังไง แค่ให้เห็นว่าเป็นจุดต่อกันแบบเดียวกับข้างบน อ่านซ้ายไปขวาได้ว่า
"บทความ → เฉพาะที่เผยแพร่แล้ว → ใหม่สุดก่อน → เอาแค่ 10 ชิ้น"
Post(ตัวใหญ่ เอกพจน์) = แม่พิมพ์ของ "บทความหนึ่งชิ้น" ในแอปบล็อก · ในภาพร้านอาหารของบทเรียน 90 คือคนดูแลสต็อกห้องบทความ ที่รู้ว่าบทความเก็บอยู่ตู้ไหน · บทนี้ยังไม่มี จะได้สร้างจริงใน Day 2publishedกับrecent= ชื่อคำสั่งที่โปรแกรมเมอร์ในทีมตั้งขึ้นเอง ไม่ใช่ของติดตัว Ruby ·limit(10)= "ขอแค่ 10" ตัวเลขในวงเล็บคือค่าที่ส่งให้คำสั่ง
- object / method
- object = ค่าที่มีคำสั่งติดตัว · method = คำสั่งแต่ละตัวนั้น · "everything is an object" คือประโยคประจำตัวของ Ruby · ถาม AI ได้ว่า "what methods does a Ruby String have for changing letter case?"
- method call (dot notation)
- การเรียก method ด้วยจุด
ค่า.method· ถ้าลงท้าย?มักคืน true/false - method chaining
- ต่อ
.methodหลายตัวติดกัน แต่ละตัวทำกับผลของตัวก่อนหน้า · พิมพ์บอก AI ได้ว่า "explain this Ruby method chain step by step" - NoMethodError
- error ตอนรันเมื่อเรียก method ที่ของชนิดนั้นไม่มี · ดูท่อน
for an instance of …ว่าของในมือเป็นชนิดอะไรจริง ๆ
5 · string — ข้อความ และการแทรกค่า
string คือข้อความ · เวลาทำเว็บเราต้องเอาค่าในตัวแปรไปใส่ในข้อความตลอด เช่น "บทความ: ข้าวมันไก่ร้านดัง" ·
ใน Go ใช้ fmt.Sprintf("บทความ: %s", title) · ใน Ruby เขียน #{ชื่อตัวแปร} ลงในข้อความตรง ๆ
เครื่องหมายคำพูดคู่ "…" = แบบฟอร์มที่มีช่องให้เติม · #{title} คือช่องว่างที่ Ruby เอาค่าของ title มากรอกให้ ·
เครื่องหมายคำพูดเดี่ยว '…' = ป้ายที่พิมพ์ตายตัว เขียนอะไรไว้ก็ได้แบบนั้นทุกตัวอักษร
ที่ไม่เหมือนกัน: แบบฟอร์มจริงมีเส้นช่องว่างให้เห็นชัด · ใน Ruby สองแบบนี้หน้าตาแทบเหมือนกัน ต่างกันแค่ขีดเดียวหรือสองขีด และถ้าใช้ผิดแบบ Ruby ไม่เตือนเลย
# quote.rb
title = "ข้าวมันไก่ร้านดัง"
puts "บทความ: #{title}"
puts 'บทความ: #{title}'
สองบรรทัดสุดท้ายต่างกันแค่เครื่องหมายคำพูด — พิมพ์อะไรออกมาบ้าง?
ผลรันจริง:
$ ruby quote.rb
บทความ: ข้าวมันไก่ร้านดัง
บทความ: #{title}
บรรทัดสองพิมพ์ #{title} ออกมาตรง ๆ ทั้งก้อน · ไม่มี error ไม่มีคำเตือน —
สไลด์หน้า 17 เรียกว่าเป็นกับดักที่คนเพิ่งเริ่มเจอบ่อยที่สุดข้อหนึ่ง ·
ใน Rails ถ้าพลาดจุดนี้ ผู้ใช้จะเห็นตัวอักษร #{...} โผล่บนหน้าเว็บ ·
(# ที่อยู่ใน "#{}" ไม่ใช่คอมเมนต์ — มันเป็นส่วนของช่องเติมค่า)
ถ้าลอง single quote ใน irb จะเห็น \ โผล่มา (ผลจริง: 'Hi #{author}' → => "Hi \#{author}") ·
\ นั่นคือ irb บอกว่า "# ตรงนี้เป็นตัวอักษรธรรมดา" · ไม่ได้อยู่ในข้อความจริง ตอน puts จะไม่เห็น
"ข้อความ" + ตัวเลข = พัง
ต่อข้อความด้วย + ได้เหมือน Go ("a" + "b" ได้ "ab") ·
แต่ถ้าอีกฝั่งเป็นตัวเลข ทั้งสองภาษาไม่ยอม — ต่างกันแค่ตอนที่ไม่ยอม:
Go — ไม่ยอมตั้งแต่ build
views := 42
s := "อ่านแล้ว " + views
// ./main.go:7:7: invalid operation:
// "อ่านแล้ว " + views
// (mismatched types untyped string and int)
(โชว์แค่ส่วนใน func main())
Ruby — รันได้จนถึงบรรทัดนั้นแล้วพัง
views = 42
puts "อ่านแล้ว " + views
# plus.rb:2:in 'String#+': no implicit
# conversion of Integer into String (TypeError)
(ผมตัด error ยาวบรรทัดเดียวให้เป็นหลายบรรทัดเพื่อให้พอดีจอ ข้อความไม่ได้แก้ · ฝั่ง Ruby ของจริงมีบรรทัด from plus.rb:2:in '<main>' ต่อท้ายอีกบรรทัด ตัดออกให้สั้น) ·
ฝั่ง Go: untyped string แค่หมายถึงข้อความที่พิมพ์ตรง ๆ ในโค้ด · ใจความคือ "string กับ int คนละชนิด บวกกันไม่ได้"
ฝั่ง Ruby: 'String#+' อ่านว่า "method ชื่อ + ของ String" — ใช่ ใน Ruby แม้แต่ + ก็เป็นปุ่มที่ติดมากับข้อความ ·
ทั้งบรรทัดแปลว่า "ปุ่ม + ของข้อความไม่แปลงตัวเลขเป็นข้อความให้เอง (TypeError = ใช้ของผิดชนิด)" ·
แก้ได้สองท่า — ผลรันจริงได้เหมือนกัน:
views = 42
puts "อ่านแล้ว " + views.to_s + " ครั้ง" # .to_s = แปลงเป็น string เอง
puts "อ่านแล้ว #{views} ครั้ง" # #{} แปลงให้อัตโนมัติ
# อ่านแล้ว 42 ครั้ง
# อ่านแล้ว 42 ครั้ง
คน Ruby เลือกท่าที่สองแทบทุกครั้ง เพราะ #{} แปลงทุกอย่างเป็นข้อความให้ ไม่ต้องจำว่าค่าไหนเป็นชนิดอะไร
nil — "ไม่มีค่า"
บางทีบทความก็ยังไม่มีคำโปรย · Ruby ใช้ค่าพิเศษชื่อ nil แปลว่า "ไม่มีค่า" ·
ใน Go ตัวแปร string ที่ยังไม่ใส่ค่าจะเป็น "" (ข้อความว่าง) แต่ใน Ruby คุณจะเจอ nil บ่อยกว่า — ผลรันจริง:
irb(main):001> subtitle = nil
=> nil
irb(main):002> subtitle
=> nil
เอา nil ไปใส่ใน #{} จะได้ช่องว่างเปล่า ไม่พัง:
puts "คำโปรย: [#{subtitle}]" พิมพ์ คำโปรย: [] (ผลรันจริง) ·
บทนี้ขอแค่จำว่า nil = ไม่มีค่า · เรื่องละเอียดและกับดักของมันอยู่ในบทเรียน 94
- string interpolation
- การแทรกค่าลงในข้อความด้วย
#{…}· ทำงานในเครื่องหมายคำพูดคู่เท่านั้น · พิมพ์บอก AI ได้ว่า "convert these string + concatenations to Ruby interpolation" - TypeError
- error ตอนรันที่บอกว่า "ของชนิดนี้ใช้ตรงนี้ไม่ได้" · มักมาคู่กับ
no implicit conversion of X into Y= "ไม่แปลง X เป็น Y ให้เอง ต้องแปลงเอง" - to_s
- method แปลงค่าเป็น string (s = string) · ตัวพี่น้องที่จะเจอคือ
to_i(เป็นจำนวนเต็ม) - nil
- ค่าที่แปลว่า "ไม่มีค่า" · เป็น object ชนิด
NilClass· คล้ายnilของ Go แต่ใน Ruby โผล่บ่อยกว่ามาก · ถาม senior ได้ว่า "ตรงนี้มีโอกาสเป็น nil ไหม" — คำถามที่ช่วยกัน bug ได้เยอะที่สุดใน Ruby
6 · ภารกิจ — ป้ายบทความหนึ่งบรรทัด
🎯 ภารกิจ (~10 นาที)
เราจะจำลองบทความหนึ่งชิ้นด้วยตัวแปรสามตัว แล้วพิมพ์ป้ายบทความออกจอ
- ใน terminal รัน
ruby -vให้เห็นว่าขึ้นต้นด้วยruby 4. - สร้างไฟล์ชื่อ
card.rbใส่ตัวแปรtitle=" hello rails "(มีช่องว่างหัวท้ายตั้งใจ) ·author="nan"·views=42 - เขียน
putsบรรทัดเดียว ให้ title ถูกตัดช่องว่างและเป็นตัวใหญ่ · author ขึ้นต้นตัวใหญ่ (ใช้ methodcapitalize) · และมียอดอ่าน — ห้ามใช้+ - รัน
ruby card.rbควรเห็น:📝 HELLO RAILS โดย Nan · อ่านแล้ว 42 ครั้ง
ถ้าเจอ error นี้ แปลว่า…
no implicit conversion of Integer into String (TypeError)→ คุณใช้+ต่อข้อความกับviews· เปลี่ยนเป็น#{views}undefined local variable or method 'titel'→ พิมพ์ชื่อตัวแปรผิด ดูบรรทัดDid you mean?ที่ Ruby เดาให้- ผลออกมาเป็น
#{title.strip.upcase}ตรงตัว → คุณใช้ single quote'…'· เปลี่ยนเป็น"…" ruby -vได้ruby 2.6.10…→ terminal ยังไม่ได้ปลุก mise (ย้อนดูหัวข้อ 1)
# card.rb
title = " hello rails "
author = "nan"
views = 42
puts "📝 #{title.strip.upcase} โดย #{author.capitalize} · อ่านแล้ว #{views} ครั้ง"
ผลรันจริง:
$ ruby card.rb
📝 HELLO RAILS โดย Nan · อ่านแล้ว 42 ครั้ง
- ใน
#{}ใส่ chain ได้เลย —title.strip.upcaseทำงานเสร็จแล้วค่อยถูกเติมลงช่อง author.capitalize= ทำตัวแรกเป็นตัวใหญ่ ที่เหลือตัวเล็กviewsเป็นตัวเลข แต่#{}แปลงให้เอง ไม่ต้อง.to_s- ตัวแปร
titleตัวเดิมยังมีช่องว่างอยู่ — method พวกนี้คืนค่าใหม่ ไม่ได้แก้ของเดิม
7 · ทดสอบความเข้าใจ
author = "Nan" แล้วรัน puts 'สวัสดี #{author}' จะเห็นอะไรบนจอ?
ตัวเลือกที่ 3 ถูก · เครื่องหมายคำพูดเดี่ยวคือ "ป้ายพิมพ์ตายตัว" ไม่มีช่องเติมค่า ·
ตัวเลือกที่ 1 จะถูกถ้าใช้ "…" · ตัวเลือกที่ 2 ผิดเพราะ Ruby ไม่ถือว่าผิด (คุณอาจตั้งใจพิมพ์แบบนั้นจริง) ·
ตัวเลือกที่ 4 คือสิ่งที่เกิดเมื่อแทรก nil ลงใน "…" ไม่ใช่กรณีนี้
จุดที่ต้องจำ: อยากแทรกค่า ต้องใช้ "…" คำพูดคู่เท่านั้น
เขียน BLOG_NAME = "a" แล้วถัดไปเขียน BLOG_NAME = "b" — Ruby ทำอะไร?
ตัวเลือกที่ 2 ถูก · ผลรันจริงได้ warning: already initialized constant แล้วค่าใหม่ถูกใช้ ·
ตัวเลือกที่ 1 คือพฤติกรรมของ Go ไม่ใช่ Ruby · ตัวเลือกที่ 3 ผิดเพราะค่าเปลี่ยนจริง ·
ตัวเลือกที่ 4 ผิดเพราะมีคำเตือนเสมอ — นั่นคือสิ่งเดียวที่ทำให้ "ค่าคงที่" ต่างจากตัวแปรธรรมดา
จุดที่ต้องจำ: ขึ้นต้นตัวใหญ่ = ค่าคงที่ · เปลี่ยนได้แต่โดนเตือน · เห็นคำเตือนนี้ = ควรแก้
ทำไม Ruby เขียน 42.even? ได้ แต่ Go เขียน views.Even() แล้ว build ไม่ผ่าน?
ตัวเลือกที่ 4 ถูก · ตัวเลข 42 ใน Ruby มีปุ่ม even? ติดมา ส่วน int ของ Go เป็นค่าเปล่าไม่มี method ·
ตัวเลือกที่ 1 ผิด — Go เช็คได้ด้วย 42%2 == 0 แค่ไม่ใช่ method ·
ตัวเลือกที่ 2 ผิด — 42.class ได้ Integer ไม่ได้แปลงอะไร ·
ตัวเลือกที่ 3 ผิด — ? เป็นแค่ตัวอักษรหนึ่งในชื่อ method
จุดที่ต้องจำ: Ruby: ค่า.method · Go: ฟังก์ชัน(ค่า)
views = 42 แล้ว puts "อ่านแล้ว " + views พังด้วย TypeError — แก้แบบที่คน Ruby นิยมที่สุดคือข้อไหน?
ตัวเลือกที่ 1 ถูก · #{} แปลงตัวเลขเป็นข้อความให้เอง ·
ตัวเลือกที่ 2 ยังพังเหมือนเดิม เพราะปัญหาอยู่ที่ + ไม่ใช่ชนิดของเครื่องหมายคำพูด ·
ตัวเลือกที่ 3 รันได้ แต่ต้องเปลี่ยนยอดอ่านเป็นข้อความ เอาไปบวกเลขต่อไม่ได้ ·
ตัวเลือกที่ 4 ยังพัง เพราะ views.class ได้ Integer ซึ่งไม่ใช่ string
จุดที่ต้องจำ: เอาค่าใส่ข้อความ ใช้ "…#{ค่า}…" ดีกว่า + เสมอ
💬 งงตรงไหน ถามกลับได้เลย — ก็อปบรรทัดที่งงไปถาม AI ว่า "อธิบายบรรทัด Ruby นี้ทีละส่วน เทียบกับ Go" หรือเปิด irb แล้วลองพิมพ์เอง เป็นวิธีที่เร็วที่สุด
ถ้าเปิดสไลด์ดูประกอบ
| หน้า | สไลด์เขียน | ของจริง | ต้องสนใจไหม |
|---|---|---|---|
| 14 | mise use -g ruby@4 แล้วได้ ruby 4.0.6 |
ruby@4 = รุ่น 4 ตัวล่าสุด ณ วันที่ติดตั้ง · เครื่องที่ตรวจได้ 4.0.9 |
ไม่ต้อง |
| 14 | ไม่ได้เขียนขั้น mise activate |
คู่มือติดตั้ง Rails ให้เพิ่มบรรทัดนี้ลง ~/.zshrc ก่อน ไม่งั้น Mac ใช้ Ruby 2.6 |
ต้อง ถ้าเพิ่งติดตั้ง |
| 14 | mise "โหลด .env ให้เอง" | ต้องเขียน [env] _.file = ".env" ใน mise.toml เอง ไม่งั้นไม่โหลด |
ยังไม่ต้อง (ยังไม่ใช้ .env ใน Day 1) |
| 14 | โชว์ mise.toml คู่กับ mise use -g |
-g จดลงไฟล์ตั้งค่าทั้งเครื่อง (~/.config/mise/config.toml) ไม่ได้สร้าง mise.toml |
ไม่ต้อง |
| 15 | class BlogPost < ApplicationRecord |
ถูกต้อง แต่ยังไม่ต้องเข้าใจ · class กับ < อยู่บทเรียน 95 · ApplicationRecord อยู่ Day 2 |
ไม่ต้อง |
| 14 | rails -v ได้ Rails 8.1.3 |
เครื่องที่ตรวจได้ 8.1.4 (รุ่นแก้บั๊ก) | ไม่ต้อง |
อ้างอิง
- Rails Guides — Install Ruby on Rails —
ลิงก์เดียวกับสไลด์หน้า 14 · อ่านหัวข้อ 1.1 (macOS) ดูบรรทัด
mise activateที่ต้องใส่ลง~/.zshrc· (คู่มือเขียนruby@3ส่วนคอร์สนี้ใช้ruby@4) - mise — Getting Started — อ่านส่วน activate ว่าทำไม terminal ต้อง "ปลุก" mise ก่อน ถึงจะสลับรุ่นให้ได้
- Ruby in Twenty Minutes —
อ่านแค่หน้าแรก (Interactive Ruby) แล้วเปิด irb ทำตาม · prompt ในหน้านั้นเป็นแบบเก่า
irb(main):001:0>ของคุณจะสั้นกว่า - Ruby From Other Languages — อ่านหัวข้อ Everything is an Object · Variable Constants · Naming conventions สั้นมาก ยืนยันเรื่องในหัวข้อ 3–4
- Ruby docs — Literals —
อ่านหัวข้อ String Literals ที่เทียบ double-quoted กับ single-quoted ว่าแบบไหนแทรก
#{}ได้ - mise — Environment variables —
ถ้าอยากรู้เรื่อง
.envในตารางสไลด์ · ดูตัวอย่าง_.file