edge
เพิ่มเติมที่ rubyonrails.org: เพิ่มเติมเกี่ยวกับ Ruby on Rails

เริ่มต้นใช้ Rails

เอกสารนี้เป็นคู่มือสำหรับการเริ่มต้นใช้ Ruby on Rails

หลังจากอ่านคู่มือนี้คุณจะรู้:

Chapters

  1. สมมติฐานในคู่มือ
  2. สวัสดี Rails!
  3. Autoloading
  4. CRUDit Where CRUDit Is Due
  5. การเพิ่มโมเดลที่สอง
  6. ความคิดเห็น1
  7. เพิ่มความคิดเห็น:
  8. การรวมรูปแบบ
  9. ความคิดเห็น2
  10. เพิ่มความคิดเห็น:(2)
  11. การลบความคิดเห็น
  12. ความปลอดภัย
  13. สิ่งที่ต่อไป?
  14. การตั้งค่าที่ควรระวัง

1 สมมติฐานในคู่มือ

คู่มือนี้ออกแบบมาสำหรับผู้เริ่มต้นที่ต้องการเริ่มสร้างแอปพลิเคชัน Rails จากศูนย์ต้นทาง ไม่ต้องการความรู้ก่อนหน้าเกี่ยวกับ Rails

Rails เป็นเฟรมเวิร์กสำหรับการพัฒนาแอปพลิเคชันเว็บที่เขียนด้วยภาษาโปรแกรม Ruby มันถูกออกแบบให้ง่ายต่อการเขียนแอปพลิเคชันเว็บโดยทำสมมติฐานเกี่ยวกับสิ่งที่นักพัฒนาทุกคนต้องการเพื่อเริ่มต้น มันช่วยให้คุณเขียนโค้ดน้อยลงในขณะที่ทำงานได้มากกว่าภาษาและเฟรมเวิร์กอื่น ๆ นักพัฒนา Rails ที่มีประสบการณ์ก็รายงานว่ามันทำให้การพัฒนาแอปพลิเคชันเว็บเป็นเรื่องสนุกขึ้น

Rails เป็นซอฟต์แวร์ที่มีความเชื่อมั่น มันสมมติว่ามี "วิธีที่ดีที่สุด" ในการทำสิ่งต่าง ๆ และถูกออกแบบให้ส่งเสริมวิธีนั้น - และในบางกรณีอาจจะปฏิเสธวิธีทางเลือก หากคุณเรียนรู้ "The Rails Way" คุณอาจค้นพบว่าความสามารถในการทำงานของคุณเพิ่มขึ้นอย่างมหาศาล หากคุณยืนกรานในการนำเอานิสัยเก่าจากภาษาอื่น ๆ มาใช้ในการพัฒนา Rails ของคุณ และพยายามใช้รูปแบบที่คุณเรียนรู้จากที่อื่น ๆ คุณอาจมีประสบการณ์ที่ไม่ดีเท่านั้น

ปรัชญาของ Rails ประกอบด้วยหลักการนำทางสองอย่างหลัก:

  • Don't Repeat Yourself (DRY): DRY เป็นหลักการในการพัฒนาซอฟต์แวร์ที่กล่าวว่า "ทุกชิ้นของความรู้ต้องมีการแสดงอย่างเดียวเท่านั้นภายในระบบ" โดยไม่ต้องเขียนข้อมูลเดียวกันซ้ำซ้อน โค้ดของเราจะง่ายต่อการบำรุงรักษา สามารถขยายได้มากขึ้น และมีข้อผิดพลาดน้อยลง
  • Convention Over Configuration: Rails มีความคิดเห็นเกี่ยวกับวิธีการที่ดีที่สุดในการทำสิ่งต่าง ๆ ในแอปพลิเคชันเว็บ และใช้ค่าเริ่มต้นของการสร้างสรรค์นี้แทนที่จะต้องระบุรายละเอียดเล็ก ๆ น้อย ๆ ผ่านไฟล์การกำหนดค่าที่ไม่สิ้นสุด สร้างโปรเจค Rails ใหม่ ----------------------------

วิธีที่ดีที่สุดในการอ่านเอกสารนี้คือการทำตามขั้นตอนทีละขั้นตอน ขั้นตอนทั้งหมดเป็นสิ่งที่จำเป็นในการเรียกใช้แอปพลิเคชันตัวอย่างนี้และไม่จำเป็นต้องเพิ่มโค้ดหรือขั้นตอนเพิ่มเติม

โดยการทำตามขั้นตอนในเอกสารนี้ คุณจะสร้างโปรเจค Rails ที่ชื่อ blog ซึ่งเป็นเว็บบล็อก (weblog) ที่ง่ายมาก ก่อนที่คุณจะเริ่มสร้างแอปพลิเคชัน คุณต้องตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง Rails เอง

หมายเหตุ: ตัวอย่างด้านล่างใช้ $ เพื่อแทนโปรมตรงของคุณในระบบปฏิบัติการแบบ UNIX แม้ว่ามันอาจถูกปรับแต่งให้แสดงผลต่างกันไป หากคุณใช้ Windows โปรมของคุณจะมีลักษณะคล้ายกับ C:\source_code>

1.1 การติดตั้ง Rails

ก่อนที่คุณจะติดตั้ง Rails คุณควรตรวจสอบเพื่อให้แน่ใจว่าระบบของคุณมีสิ่งที่จำเป็นติดตั้งไว้ รวมถึง:

  • Ruby
  • SQLite3

1.1.1 การติดตั้ง Ruby

เปิดโปรแกรมคอมมานด์ไลน์ (command line prompt) บน macOS เปิด Terminal.app บน Windows เลือก "Run" จากเมนู Start และพิมพ์ cmd.exe คำสั่งใดๆที่มีเครื่องหมายดอลลาร์ $ นำหน้าควรรันในโปรแกรมคอมมานด์ไลน์ ตรวจสอบว่าคุณได้ติดตั้ง Ruby เวอร์ชันปัจจุบัน:

$ ruby --version
ruby 2.7.0

Rails ต้องการ Ruby เวอร์ชัน 2.7.0 หรือใหม่กว่า แนะนำให้ใช้เวอร์ชันล่าสุดของ Ruby หากเลขเวอร์ชันที่แสดงออกมาน้อยกว่า (เช่น 2.3.7 หรือ 1.8.7) คุณจะต้องติดตั้ง Ruby ใหม่

ในการติดตั้ง Rails บน Windows คุณจะต้องติดตั้ง Ruby Installer ก่อน

สำหรับวิธีการติดตั้งอื่นๆสำหรับระบบปฏิบัติการส่วนใหญ่ โปรดดูที่ ruby-lang.org

1.1.2 การติดตั้ง SQLite3

คุณยังต้องติดตั้งฐานข้อมูล SQLite3 อีกด้วย ระบบปฏิบัติการแบบ UNIX ที่ได้รับความนิยมมักจะมี SQLite3 เวอร์ชันที่เหมาะสม สำหรับระบบปฏิบัติการอื่นๆ สามารถหาคำแนะนำการติดตั้งได้ที่เว็บไซต์ SQLite3

ตรวจสอบว่าติดตั้งถูกต้องและอยู่ใน PATH ของคุณ:

$ sqlite3 --version

โปรแกรมควรรายงานเวอร์ชัน

1.1.3 การติดตั้ง Rails

ในการติดตั้ง Rails ให้ใช้คำสั่ง gem install ที่ RubyGems จัดหาให้:

$ gem install rails

เพื่อตรวจสอบว่าคุณติดตั้งทุกอย่างถูกต้อง คุณควรสามารถรันคำสั่งต่อไปนี้ในโปรแกรมคอมมานด์ไลน์ใหม่:

$ rails --version

หากมีข้อความที่บอกว่า "Rails 7.0.0" คุณพร้อมที่จะดำเนินการต่อ

1.2 การสร้างแอปพลิเคชันบล็อก

Rails มาพร้อมกับสคริปต์ต่างๆที่เรียกว่า generators ซึ่งออกแบบมาเพื่อทำให้งานการพัฒนาของคุณง่ายขึ้นโดยการสร้างทุกอย่างที่จำเป็นในการเริ่มต้นทำงานในงานที่เฉพาะเจาะจง หนึ่งในนั้นคือ generator ของแอปพลิเคชันใหม่ ซึ่งจะให้คุณได้รับพื้นฐานของแอปพลิเคชัน Rails ใหม่เพื่อให้คุณไม่ต้องเขียนเอง ในการใช้เครื่องมือสร้างนี้ ให้เปิด terminal และนำทางไปยังไดเรกทอรีที่คุณมีสิทธิ์ในการสร้างไฟล์ แล้วรันคำสั่งต่อไปนี้:

$ rails new blog

นี้จะสร้างแอปพลิเคชัน Rails ที่ชื่อ Blog ในไดเรกทอรี blog และติดตั้ง gem dependencies ที่ได้กล่าวถึงใน Gemfile โดยใช้ bundle install.

เคล็ดลับ: คุณสามารถดูตัวเลือกคำสั่งทั้งหมดที่เครื่องมือสร้างแอปพลิเคชัน Rails รองรับได้โดยรันคำสั่ง rails new --help.

หลังจากสร้างแอปพลิเคชันบล็อกแล้ว ให้เปลี่ยนไปยังโฟลเดอร์ของมัน:

$ cd blog

ไดเรกทอรี blog จะมีไฟล์และโฟลเดอร์ที่สร้างขึ้นมาหลายรายการที่เป็นส่วนประกอบของโครงสร้างของแอปพลิเคชัน Rails ส่วนใหญ่ของงานในบทแนะนำนี้จะเกิดขึ้นในโฟลเดอร์ app แต่นี่คือการอธิบายพื้นฐานเกี่ยวกับฟังก์ชันของแต่ละไฟล์และโฟลเดอร์ที่ Rails สร้างโดยค่าเริ่มต้น:

ไฟล์/โฟลเดอร์ วัตถุประสงค์
app/ มีควบคุมเกี่ยวกับ controllers, models, views, helpers, mailers, channels, jobs, และ assets สำหรับแอปพลิเคชันของคุณ คุณจะใช้โฟลเดอร์นี้ในส่วนที่เหลือของคู่มือนี้
bin/ มีสคริปต์ rails ที่ใช้เริ่มแอปพลิเคชันของคุณและอาจมีสคริปต์อื่น ๆ ที่คุณใช้ในการตั้งค่า อัปเดต ใช้งาน หรือรันแอปพลิเคชันของคุณ
config/ มีการตั้งค่าสำหรับเส้นทางของแอปพลิเคชัน ฐานข้อมูล และอื่น ๆ นี่จะอธิบายอย่างละเอียดมากขึ้นใน การกำหนดค่าแอปพลิเคชัน Rails
config.ru การกำหนดค่า Rack สำหรับเซิร์ฟเวอร์ที่ใช้ Rack เพื่อเริ่มแอปพลิเคชัน สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Rack ดูที่ เว็บไซต์ Rack
db/ มีแผนฐานข้อมูลปัจจุบันของคุณรวมถึงการเคลื่อนย้ายฐานข้อมูล
Gemfile
Gemfile.lock
ไฟล์เหล่านี้ช่วยให้คุณระบุว่า gem dependencies ใดที่จำเป็นสำหรับแอปพลิเคชัน Rails ของคุณ ไฟล์เหล่านี้ถูกใช้โดย Bundler gem สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ Bundler ดูที่ เว็บไซต์ Bundler
lib/ โมดูลที่ถูกขยายสำหรับแอปพลิเคชันของคุณ
log/ ไฟล์บันทึกแอปพลิเคชัน
public/ มีไฟล์และคอมไพล์แอสเซ็ตแบบสถิต ขณะที่แอปของคุณกำลังทำงานโฟลเดอร์นี้จะถูกเปิดเผยอย่างเดียว
Rakefile ไฟล์นี้ค้นหาและโหลดงานที่สามารถรันได้จาก command line การกำหนดงานถูกกำหนดไว้ทั่วทั้งส่วนประกอบของ Rails แทนที่จะเปลี่ยน Rakefile คุณควรเพิ่มงานของคุณเองโดยเพิ่มไฟล์ในโฟลเดอร์ lib/tasks ของแอปพลิเคชันของคุณ
README.md นี่เป็นคู่มือคำสั่งสั้น ๆ สำหรับแอปพลิเคชันของคุณ คุณควรแก้ไขไฟล์นี้เพื่อบอกผู้อื่นว่าแอปพลิเคชันของคุณทำอะไร วิธีการตั้งค่า และอื่น ๆ
storage/ ไฟล์ Active Storage สำหรับ Disk Service นี้อธิบายอย่างละเอียดใน ภาพรวม Active Storage
test/ เครื่องมือทดสอบหน่วย คำสั่งติดตั้ง และอุปกรณ์ทดสอบอื่น ๆ นี้อธิบายอย่างละเอียดใน การทดสอบแอปพลิเคชัน Rails
tmp/ ไฟล์ชั่วคราว (เช่นแคชและไฟล์ pid)
vendor/ สถานที่สำหรับโค้ดจากบุคคลที่สาม ในแอปพลิเคชัน Rails ปกตินี้รวมถึง gem ที่ขาย
.gitattributes ไฟล์นี้กำหนดข้อมูลเมตาดาต้าสำหรับเส้นทางที่ระบุในรีพอสิทอรี git ข้อมูลเมตาดาต้าเหล่านี้สามารถใช้โดย git และเครื่องมืออื่น ๆ เพื่อเพิ่มประสิทธิภาพของพฤติกรรมของพวกเขา ดูที่ เอกสาร gitattributes สำหรับข้อมูลเพิ่มเติม
.gitignore ไฟล์นี้บอก git ว่าไฟล์ (หรือรูปแบบ) ใดที่ควรถูกละเว้น ดูที่ GitHub - การละเว้นไฟล์ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการละเว้นไฟล์
.ruby-version ไฟล์นี้มีรุ่น Ruby เริ่มต้น

2 สวัสดี Rails!

เริ่มต้นด้วยการนำข้อความขึ้นหน้าจอโดยรวดเร็ว ในการทำนี้คุณต้องเริ่มเซิร์ฟเวอร์แอปพลิเคชัน Rails ของคุณ

2.1 เริ่มต้นเว็บเซิร์ฟเวอร์

คุณมีแอปพลิเคชัน Rails ที่ใช้งานได้แล้วจริงๆ หากต้องการดูแอปพลิเคชันนี้ คุณต้องเริ่มเว็บเซิร์ฟเวอร์บนเครื่องพัฒนาของคุณ คุณสามารถทำได้โดยรันคำสั่งต่อไปนี้ในไดเรกทอรี blog:

$ bin/rails server

เคล็ดลับ: หากคุณใช้ Windows คุณต้องส่งสคริปต์ในโฟลเดอร์ bin โดยตรงไปยังตัวแปลงรูบี เช่น ruby bin\rails server.

เคล็ดลับ: การบีบอัด JavaScript asset ต้องการ JavaScript runtime ที่พร้อมใช้งานบนระบบของคุณ หากไม่มี runtime คุณจะเห็นข้อผิดพลาด execjs ระหว่างการบีบอัด asset โดยทั่วไป macOS และ Windows มาพร้อมกับ JavaScript runtime ที่ติดตั้งแล้ว therubyrhino เป็น runtime ที่แนะนำสำหรับผู้ใช้ JRuby และถูกเพิ่มเข้าไปใน Gemfile โดยค่าเริ่มต้นในแอปที่สร้างขึ้นภายใต้ JRuby คุณสามารถสำรวจ runtime ที่รองรับได้ทั้งหมดที่ ExecJS.

นี้จะเริ่ม Puma เว็บเซิร์ฟเวอร์ที่กระจายพร้อมกับ Rails โดยค่าเริ่มต้น เพื่อดูแอปพลิเคชันของคุณในการทำงาน เปิดหน้าต่างเบราว์เซอร์และไปยัง http://localhost:3000 คุณควรเห็นหน้าข้อมูลเริ่มต้นของ Rails:

รูปหน้าเริ่มต้นของ Rails

เมื่อคุณต้องการหยุดเว็บเซิร์ฟเวอร์ ให้กด Ctrl+C ในหน้าต่างเทอร์มินัลที่เซิร์ฟเวอร์กำลังทำงานอยู่ ในสภาพแวดล้อมการพัฒนา Rails ไม่จำเป็นต้องรีสตาร์ทเซิร์ฟเวอร์; การเปลี่ยนแปลงที่คุณทำในไฟล์จะถูกรับรู้โดยอัตโนมัติโดยเซิร์ฟเวอร์

หน้าเริ่มต้นของ Rails เป็นการทดสอบการทำงานของแอปพลิเคชัน Rails ใหม่: มันตรวจสอบให้แน่ใจว่าคุณได้กำหนดค่าซอฟต์แวร์ของคุณอย่างถูกต้องพอที่จะให้บริการหน้าเว็บ

2.2 พูด "สวัสดี" Rails

ในการให้ Rails พูด "สวัสดี" คุณต้องสร้างอย่างน้อย เส้นทาง (route), คอนโทรลเลอร์ (controller) พร้อม แอ็คชัน (action), และ วิว (view) เส้นทางจะแมปคำขอไปยังแอคชันของคอนโทรลเลอร์ แอคชันของคอนโทรลเลอร์จะดำเนินการที่จำเป็นเพื่อจัดการคำขอ และเตรียมข้อมูลสำหรับวิว วิวจะแสดงข้อมูลในรูปแบบที่ต้องการ

ในเชิงการดำเนินการ: เส้นทางเป็นกฎที่เขียนใน Ruby DSL (Domain-Specific Language) คอนโทรลเลอร์เป็นคลาส Ruby และเมธอดสาธารณะของคอนโทรลเลอร์คือแอคชัน และวิวเป็นเทมเพลตที่เขียนโดยใช้ HTML และ Ruby ร่วมกัน

เรามาเริ่มต้นด้วยการเพิ่มเส้นทางลงในไฟล์เส้นทาง config/routes.rb ที่บล็อก Rails.application.routes.draw ด้านบน:

Rails.application.routes.draw do
  get "/articles", to: "articles#index"

  # สำหรับรายละเอียดเกี่ยวกับ DSL ที่ใช้ในไฟล์นี้ โปรดดูที่ https://guides.rubyonrails.org/routing.html
end

เส้นทางด้านบนประกาศว่า GET /articles จะถูกแมปไปยัง index action ของ ArticlesController

เพื่อสร้าง ArticlesController และ index action เราจะใช้คำสั่ง controller generator (พร้อมกับตัวเลือก --skip-routes เนื่องจากเรามีเส้นทางที่เหมาะสมอยู่แล้ว):

$ bin/rails generate controller Articles index --skip-routes

Rails จะสร้างไฟล์หลายๆ ไฟล์ให้เรา:

create  app/controllers/articles_controller.rb
invoke  erb
create    app/views/articles
create    app/views/articles/index.html.erb
invoke  test_unit
create    test/controllers/articles_controller_test.rb
invoke  helper
create    app/helpers/articles_helper.rb
invoke    test_unit

ไฟล์ที่สำคัญที่สุดคือไฟล์ controller app/controllers/articles_controller.rb มาดูกัน:

class ArticlesController < ApplicationController
  def index
  end
end

index action ว่างเปล่า ถ้า action ไม่ได้เรียกใช้งาน view โดยชัดเจน (หรือไม่ได้เรียกใช้งานการตอบสนอง HTTP ใดๆ) Rails จะทำการเรียกใช้งาน view ที่ตรงกันกับชื่อของ controller และ action โดยอัตโนมัติ ตามหลัก Convention Over Configuration! View จะอยู่ในไดเรกทอรี app/views ดังนั้น action index จะเรียกใช้งาน app/views/articles/index.html.erb โดยค่าเริ่มต้น

เรามาเปิด app/views/articles/index.html.erb และแทนที่เนื้อหาด้วย:

<h1>Hello, Rails!</h1>

หากคุณหยุดเว็บเซิร์ฟเวอร์ก่อนที่จะเรียกใช้งาน controller generator ให้เริ่มเว็บเซิร์ฟเวอร์ใหม่ด้วย bin/rails server ตอนนี้เราเข้าไปที่ http://localhost:3000/articles และเราจะเห็นข้อความของเราที่แสดงอยู่!

2.3 ตั้งค่าหน้าแรกของแอปพลิเคชัน

ขณะนี้ http://localhost:3000 ยังแสดงหน้าที่มีโลโก้ของ Ruby on Rails เรามาแสดงข้อความ "Hello, Rails!" ที่ http://localhost:3000 เช่นกัน เพื่อทำเช่นนั้น เราจะเพิ่มเส้นทางที่แมป root path ของแอปพลิเคชันของเราไปยัง controller และ action ที่เหมาะสม

เรามาเปิด config/routes.rb และเพิ่ม root route ต่อไปนี้ไว้ที่ด้านบนของบล็อก Rails.application.routes.draw:

Rails.application.routes.draw do
  root "articles#index"

  get "/articles", to: "articles#index"
end

ตอนนี้เราสามารถเห็นข้อความ "Hello, Rails!" เมื่อเราเข้าไปที่ http://localhost:3000 ซึ่งยืนยันว่าเส้นทาง root ยังถูกแมปไปยัง index action ของ ArticlesController อีกด้วย

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับเส้นทาง ดูที่ Rails Routing from the Outside In.

3 Autoloading

แอปพลิเคชัน Rails ไม่ ใช้ require เพื่อโหลดโค้ดของแอปพลิเคชัน

คุณอาจจะสังเกตเห็นว่า ArticlesController สืบทอดมาจาก ApplicationController แต่ app/controllers/articles_controller.rb ไม่มีอะไรเช่น

require "application_controller" # อย่าทำเช่นนี้

คลาสและโมดูลของแอปพลิเคชันสามารถใช้งานได้ทุกที่ คุณไม่จำเป็นต้องและ ไม่ควร โหลดอะไรที่อยู่ใต้ app ด้วย require ฟีเจอร์นี้เรียกว่า autoloading และคุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับมันได้ที่ Autoloading and Reloading Constants.

คุณต้องใช้ require เฉพาะสำหรับสองกรณีใช้งาน:

  • เพื่อโหลดไฟล์ที่อยู่ในไดเรกทอรี lib
  • เพื่อโหลด dependency ของ gem ที่มี require: false ใน Gemfile MVC และคุณ -----------

จนถึงตอนนี้เราได้พูดถึงเรื่องของเส้นทาง (routes), คอนโทรลเลอร์ (controllers), แอ็กชัน (actions), และวิว (views) ทั้งหมดนี้เป็นส่วนประกอบที่ตามมาตรฐานของแอปพลิเคชันเว็บที่ใช้รูปแบบ MVC (Model-View-Controller) ซึ่งเป็นรูปแบบการออกแบบที่แบ่งหน้าที่ของแอปพลิเคชันเพื่อให้ง่ายต่อการคิดเช่นเดียวกัน รูปแบบนี้ถูกใช้ใน Rails ตามความเป็นที่

เนื่องจากเรามีคอนโทรลเลอร์และวิวที่จะทำงานร่วมกัน ให้เราสร้างส่วนถัดไป: โมเดล

3.1 การสร้างโมเดล

โมเดล เป็นคลาส Ruby ที่ใช้แทนข้อมูล นอกจากนี้ โมเดลยังสามารถทำงานร่วมกับฐานข้อมูลของแอปพลิเคชันผ่านคุณสมบัติ Active Record ของ Rails

ในการกำหนดโมเดล เราจะใช้เครื่องมือสร้างโมเดลดังนี้:

$ bin/rails generate model Article title:string body:text

หมายเหตุ: ชื่อโมเดลจะเป็นรูปกริยาในรูปเอกพจน์ เนื่องจากโมเดลที่ถูกสร้างขึ้นแทนข้อมูลเดียว ในการจดจำกฎแนวทางนี้ คิดว่าถ้าเราต้องการเรียกใช้คอนสตรัคเตอร์ของโมเดล เราต้องเขียน Article.new(...) และไม่ใช่ Articles.new(...)

การสร้างคำสั่งดังกล่าวจะสร้างไฟล์หลายไฟล์ดังนี้:

invoke  active_record
create    db/migrate/<timestamp>_create_articles.rb
create    app/models/article.rb
invoke    test_unit
create      test/models/article_test.rb
create      test/fixtures/articles.yml

ไฟล์สองไฟล์ที่เราจะให้ความสนใจคือไฟล์ migration (db/migrate/<timestamp>_create_articles.rb) และไฟล์โมเดล (app/models/article.rb)

3.2 การเปลี่ยนแปลงฐานข้อมูล

การเปลี่ยนแปลงฐานข้อมูล ใช้สำหรับเปลี่ยนโครงสร้างของฐานข้อมูลในแอปพลิเคชัน ในแอปพลิเคชัน Rails การเปลี่ยนแปลงฐานข้อมูลเขียนด้วยภาษา Ruby เพื่อให้สามารถใช้กับฐานข้อมูลที่แตกต่างกันได้

มาดูเนื้อหาในไฟล์ migration ใหม่ของเรา:

class CreateArticles < ActiveRecord::Migration[7.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :body

      t.timestamps
    end
  end
end

การเรียกใช้ create_table ระบุวิธีการสร้างตาราง articles โดยค่าเริ่มต้น create_table จะเพิ่มคอลัมน์ id เป็น primary key ที่เพิ่มขึ้นอัตโนมัติ ดังนั้นแถวแรกในตารางจะมี id เป็น 1 แถวถัดไปจะมี id เป็น 2 และอื่น ๆ

ภายในบล็อกสำหรับ create_table กำหนดคอลัมน์สองคอลัมน์คือ title และ body คอลัมน์เหล่านี้ถูกเพิ่มโดยเครื่องมือสร้างเนื่องจากเราระบุในคำสั่ง generate (bin/rails generate model Article title:string body:text)

บรรทัดสุดท้ายของบล็อกเป็นการเรียก t.timestamps เมธอดนี้กำหนดคอลัมน์เพิ่มเติมสองคอลัมน์ชื่อ created_at และ updated_at ดังที่เราจะเห็น Rails จะจัดการให้เราโดยการกำหนดค่าเมื่อเราสร้างหรืออัปเดตออบเจกต์โมเดล

ให้เราเรียกใช้การเปลี่ยนแปลงฐานข้อมูลด้วยคำสั่งต่อไปนี้:

$ bin/rails db:migrate

คำสั่งจะแสดงผลลัพธ์ที่แสดงว่าตารางถูกสร้างขึ้น: ``` == CreateArticles: กำลังทำการโยกย้าย =================================== -- create_table(:articles) -> 0.0018s == CreateArticles: โยกย้ายเสร็จสิ้น (0.0018s) ==========================

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการโยกย้าย โปรดดู Active Record Migrations.

ตอนนี้เราสามารถใช้โมเดลเพื่อทำงานกับตารางได้แล้ว

3.3 การใช้โมเดลเพื่อทำงานกับฐานข้อมูล

เพื่อทดลองใช้โมเดลของเราเล็กน้อย เราจะใช้คุณสมบัติของ Rails ที่เรียกว่า console คอนโซลเป็นสภาพแวดล้อมการเขียนโค้ดแบบแบบป้อนเข้า คล้ายกับ irb แต่มันยังโหลด Rails และโค้ดแอปพลิเคชันของเราโดยอัตโนมัติ

ให้เราเริ่มคอนโซลด้วยคำสั่งนี้:

$ bin/rails console

คุณควรเห็นโปรโมป์ irb เช่น:

Loading development environment (Rails 7.0.0)
irb(main):001:0>

ที่โปรโมป์นี้ เราสามารถสร้างอ็อบเจ็กต์ Article ใหม่ได้:

irb> article = Article.new(title: "Hello Rails", body: "I am on Rails!")

สำคัญที่จะระบุว่าเราเพียงแค่ เริ่มต้น อ็อบเจ็กต์นี้เท่านั้น อ็อบเจ็กต์นี้ยังไม่ได้ถูกบันทึกลงในฐานข้อมูลเลย มันมีอยู่เฉพาะในคอนโซลเท่านั้น หากต้องการบันทึกอ็อบเจ็กต์ลงในฐานข้อมูล เราต้องเรียกใช้ save:

irb> article.save
(0.1ms)  begin transaction
Article Create (0.4ms)  INSERT INTO "articles" ("title", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "Hello Rails"], ["body", "I am on Rails!"], ["created_at", "2020-01-18 23:47:30.734416"], ["updated_at", "2020-01-18 23:47:30.734416"]]
(0.9ms)  commit transaction
=> true

ผลลัพธ์ด้านบนแสดงคิวรีฐานข้อมูล INSERT INTO "articles" ... ซึ่งแสดงว่าบทความถูกแทรกลงในตารางของเราแล้ว และหากเรามองอ็อบเจ็กต์ article อีกครั้ง เราจะเห็นว่ามีสิ่งที่น่าสนใจเกิดขึ้น:

irb> article
=> #<Article id: 1, title: "Hello Rails", body: "I am on Rails!", created_at: "2020-01-18 23:47:30", updated_at: "2020-01-18 23:47:30">

แอตทริบิวต์ id, created_at, และ updated_at ของอ็อบเจ็กต์ถูกตั้งค่าแล้ว รูปแบบนี้ถูก Rails ทำให้เราเมื่อเราบันทึกอ็อบเจ็กต์

เมื่อเราต้องการเรียกดูบทความนี้จากฐานข้อมูล เราสามารถเรียกใช้ find บนโมเดลและส่ง id เป็นอาร์กิวเมนต์:

irb> Article.find(1)
=> #<Article id: 1, title: "Hello Rails", body: "I am on Rails!", created_at: "2020-01-18 23:47:30", updated_at: "2020-01-18 23:47:30">

และเมื่อเราต้องการเรียกดูบทความทั้งหมดจากฐานข้อมูล เราสามารถเรียกใช้ all บนโมเดลได้:

irb> Article.all
=> #<ActiveRecord::Relation [#<Article id: 1, title: "Hello Rails", body: "I am on Rails!", created_at: "2020-01-18 23:47:30", updated_at: "2020-01-18 23:47:30">]>

เมธอดนี้จะส่งกลับอ็อบเจ็กต์ ActiveRecord::Relation ซึ่งคุณสามารถคิดเป็นอาร์เรย์ที่มีความสามารถพิเศษได้ เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับโมเดล โปรดดู Active Record Basics และ Active Record Query Interface.

โมเดลเป็นส่วนสุดท้ายของปริภูมิประกอบ MVC ต่อไปเราจะเชื่อมต่อส่วนทั้งหมดเข้าด้วยกัน

3.4 แสดงรายการบทความ

ให้เรากลับไปที่คอนโทรลเลอร์ใน app/controllers/articles_controller.rb และเปลี่ยนการทำงานของ index เพื่อดึงข้อมูลบทความทั้งหมดจากฐานข้อมูล:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end
end

ตัวแปรอินสแตนซ์ของคอนโทรลเลอร์สามารถเข้าถึงได้จากวิว นั่นหมายความว่าเราสามารถอ้างอิง @articles ใน app/views/articles/index.html.erb ได้ ให้เราเปิดไฟล์นั้นและแทนที่เนื้อหาด้วย:

<h1>บทความ</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= article.title %>
    </li>
  <% end %>
</ul>

โค้ดด้านบนเป็นการผสมผสานระหว่าง HTML และ ERB ERB เป็นระบบเทมเพลตที่ประเมินรหัส Ruby ที่ฝังอยู่ในเอกสาร ที่นี่เราสามารถเห็นสองประเภทของแท็ก ERB: <% %> และ <%= %> แท็ก <% %> หมายถึง "ประเมินรหัส Ruby ที่อยู่ในแท็ก" และแท็ก <%= %> หมายถึง "ประเมินรหัส Ruby ที่อยู่ในแท็ก และแสดงผลค่าที่คืนกลับ" สิ่งใดก็ตามที่คุณสามารถเขียนในโปรแกรม Ruby ปกติสามารถใส่ไว้ในแท็ก ERB เหล่านี้ได้ แม้ว่าจะเป็นที่ดีที่สุดที่จะเก็บเนื้อหาของแท็ก ERB ให้สั้น เพื่อความอ่านง่าย

เนื่องจากเราไม่ต้องการแสดงผลค่าที่คืนจาก @articles.each เราจึงใส่รหัสนั้นใน <% %> แต่เนื่องจากเราต้องการแสดงผลค่าที่คืนจาก article.title (สำหรับแต่ละบทความ) เราจึงใส่รหัสนั้นใน <%= %>

เราสามารถดูผลลัพธ์สุดท้ายได้โดยเข้าชม http://localhost:3000 (โปรดจำไว้ว่า bin/rails server ต้องทำงานอยู่!) นี่คือสิ่งที่เกิดขึ้นเมื่อเราทำเช่นนั้น:

  1. เบราว์เซอร์ทำการร้องขอ: GET http://localhost:3000.
  2. แอปพลิเคชัน Rails ของเราได้รับคำขอนี้
  3. เราเชื่อมต่อเส้นทางของ Rails กับการทำงาน index ของ ArticlesController
  4. การทำงาน index ใช้โมเดล Article เพื่อดึงบทความทั้งหมดในฐานข้อมูล
  5. Rails จะแสดงผลวิว app/views/articles/index.html.erb อัตโนมัติ
  6. รหัส ERB ในวิวจะถูกประเมินเพื่อแสดงผล HTML
  7. เซิร์ฟเวอร์จะส่งการตอบกลับที่มี HTML กลับไปยังเบราว์เซอร์

เราได้เชื่อมต่อส่วนประกอบ MVC ทั้งหมดเข้าด้วยกันและเรามีการทำงานของคอนโทรลเลอร์ครั้งแรก! ต่อไปเราจะไปทำงานกับคอนโทรลเลอร์ที่สอง

4 CRUDit Where CRUDit Is Due

เกือบทุกแอปพลิเคชันเว็บเกี่ยวข้องกับการดำเนินการ CRUD (สร้าง อ่าน อัปเดต และลบ) คุณอาจพบว่างานส่วนใหญ่ที่แอปพลิเคชันของคุณทำคือ CRUD Rails รับรู้ถึงสิ่งนี้และมีคุณสมบัติหลายอย่างที่ช่วยให้การเขียนโค้ดที่ทำ CRUD ง่ายขึ้น เราจะเริ่มการสำรวจคุณสมบัติเหล่านี้โดยการเพิ่มฟังก์ชันเพิ่มเติมให้กับแอปพลิเคชันของเรา

4.1 แสดงบทความเดียว

ขณะนี้เรามีมุมมองที่แสดงรายการบทความทั้งหมดในฐานข้อมูลของเรา ให้เราเพิ่มมุมมองใหม่ที่แสดงชื่อและเนื้อหาของบทความเดียว

เราเริ่มต้นด้วยการเพิ่มเส้นทางใหม่ที่จะแมปไปยังการกระทำของคอนโทรลเลอร์ใหม่ (ซึ่งเราจะเพิ่มต่อไป) เปิด config/routes.rb และแทรกเส้นทางสุดท้ายที่แสดงด้านล่างนี้:

Rails.application.routes.draw do
  root "articles#index"

  get "/articles", to: "articles#index"
  get "/articles/:id", to: "articles#show"
end

เส้นทางใหม่เป็นเส้นทาง get อีกเส้นทางหนึ่ง แต่มีสิ่งพิเศษเพิ่มเติมในเส้นทางของมัน: :id สิ่งนี้กำหนดเส้นทาง พารามิเตอร์ เส้นทางพารามิเตอร์จะจับเซกเมนต์ของเส้นทางของคำขอ และใส่ค่านั้นลงใน params Hash ซึ่งสามารถเข้าถึงได้โดยการกระทำของคอนโทรลเลอร์ ตัวอย่างเช่น เมื่อจัดการคำขอเช่น GET http://localhost:3000/articles/1 1 จะถูกจับเป็นค่าสำหรับ :id ซึ่งจากนั้นจะสามารถเข้าถึงได้เป็น params[:id] ในการกระทำ show ของ ArticlesController

เรามาเพิ่มการกระทำ show ตอนนี้ ด้านล่างของการกระทำ index ใน app/controllers/articles_controller.rb:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end
end

การกระทำ show เรียกใช้ Article.find (กล่าวถึงไว้ก่อนหน้านี้) ด้วย ID ที่จับได้จากพารามิเตอร์เส้นทาง บทความที่ได้รับคืนจะถูกเก็บไว้ในตัวแปร @article เพื่อให้สามารถเข้าถึงได้จากมุมมอง โดยค่าเริ่มต้นการกระทำ show คือการแสดงผล app/views/articles/show.html.erb

มาสร้าง app/views/articles/show.html.erb ด้วยเนื้อหาดังต่อไปนี้:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

ตอนนี้เราสามารถดูบทความเมื่อเราเข้าชม http://localhost:3000/articles/1!

เพื่อจบการทำงาน เรามาเพิ่มวิธีที่สะดวกในการเข้าถึงหน้าของบทความ โดยเราจะเชื่อมโยงชื่อบทความแต่ละรายการใน app/views/articles/index.html.erb ไปยังหน้าของบทความ:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <a href="/articles/<%= article.id %>">
        <%= article.title %>
      </a>
    </li>
  <% end %>
</ul>

4.2 การกำหนดเส้นทางทรัพยากร

จนถึงตอนนี้ เราได้ครอบคลุม "R" (อ่าน) ของ CRUD แล้ว เราจะครอบคลุม "C" (สร้าง) "U" (อัปเดต) และ "D" (ลบ) ในภายหลัง ตามที่คุณอาจเดาได้ เราจะทำโดยการเพิ่มเส้นทาง การกระทำของคอนโทรลเลอร์ และมุมมองใหม่ เมื่อเรามีการรวมกันของเส้นทาง การกระทำของคอนโทรลเลอร์ และมุมมองที่ทำงานร่วมกันเพื่อดำเนินการ CRUD บนสิ่งที่เรียกว่า ทรัพยากร ตัวอย่างเช่น ในแอปพลิเคชันของเรา เราจะพูดถึงว่าบทความเป็นทรัพยากร

Rails มีเมธอดเส้นทางชื่อ resources ซึ่งจะแมปเส้นทางทั้งหมดที่เป็นไปตามปกติสำหรับคอลเลกชันของทรัพยากร เช่น บทความ ดังนั้นก่อนที่เราจะไปที่ส่วน "C" "U" และ "D" เรามาแทนที่เส้นทาง get สองเส้นใน config/routes.rb ด้วย resources: ```ruby Rails.application.routes.draw do root "articles#index"

resources :articles end ```

เราสามารถตรวจสอบเส้นทางที่ถูกจับคู่ได้โดยการรันคำสั่ง bin/rails routes:

$ bin/rails routes
      Prefix Verb   URI Pattern                  Controller#Action
        root GET    /                            articles#index
    articles GET    /articles(.:format)          articles#index
 new_article GET    /articles/new(.:format)      articles#new
     article GET    /articles/:id(.:format)      articles#show
             POST   /articles(.:format)          articles#create
edit_article GET    /articles/:id/edit(.:format) articles#edit
             PATCH  /articles/:id(.:format)      articles#update
             DELETE /articles/:id(.:format)      articles#destroy

เมธอด resources ยังตั้งค่า URL และเมธอดช่วยในการเข้าถึงที่เราสามารถใช้ได้ เพื่อให้โค้ดของเราไม่ขึ้นอยู่กับการกำหนดค่าเส้นทางเฉพาะ ค่าในคอลัมน์ "Prefix" ที่แสดงด้านบนรวมกับคำต่อท้าย _url หรือ _path จะเป็นชื่อของเมธอดช่วยเหล่านี้ ตัวอย่างเช่น เมธอดช่วย article_path จะคืนค่า "/articles/#{article.id}" เมื่อได้รับบทความ สามารถใช้เพื่อจัดการลิงก์ใน app/views/articles/index.html.erb:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <a href="<%= article_path(article) %>">
        <%= article.title %>
      </a>
    </li>
  <% end %>
</ul>

อย่างไรก็ตาม เราจะทำไปอีกขั้นตอนหนึ่งโดยใช้ link_to เมธอดช่วย เมธอดช่วย link_to จะแสดงลิงก์โดยใช้อาร์กิวเมนต์แรกเป็นข้อความของลิงก์ และอาร์กิวเมนต์ที่สองเป็นปลายทางของลิงก์ หากเราส่งวัตถุโมเดลเป็นอาร์กิวเมนต์ที่สอง link_to จะเรียกใช้เมธอดช่วยเส้นทางที่เหมาะสมเพื่อแปลงวัตถุเป็นเส้นทาง ตัวอย่างเช่น หากเราส่งบทความ link_to จะเรียกใช้ article_path ดังนั้น app/views/articles/index.html.erb กลายเป็น:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= link_to article.title, article %>
    </li>
  <% end %>
</ul>

ดีมาก!

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับเส้นทาง ดูที่ Rails Routing from the Outside In.

4.3 สร้างบทความใหม่

ตอนนี้เราไปที่ "C" (สร้าง) ของ CRUD โดยทั่วไปในแอปพลิเคชันเว็บ การสร้างทรัพยากรใหม่เป็นกระบวนการหลายขั้นตอน ก่อนอื่นผู้ใช้จะขอแบบฟอร์ม เพื่อกรอกข้อมูล จากนั้นผู้ใช้จะส่งแบบฟอร์ม หากไม่มีข้อผิดพลาด ทรัพยากรจะถูกสร้างและแสดงข้อความยืนยันใด ๆ นอกเหนือจากนี้ แบบฟอร์มจะถูกแสดงอีกครั้งพร้อมกับข้อความข้อผิดพลาด และกระบวนการจะถูกทำซ้ำ

ในแอปพลิเคชัน Rails ขั้นตอนเหล่านี้จะถูกจัดการตามความสามารถของคอนโทรลเลอร์ new และ create ของคอนโทรลเลอร์ มาเพิ่มการดำเนินการเหล่านี้ใน app/controllers/articles_controller.rb ด้านล่างของการดำเนินการ show:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(title: "...", body: "...")

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end
end

การกระทำ new จะสร้างอินสแตนซ์ของบทความใหม่ แต่ไม่บันทึกไว้ บทความนี้จะถูกใช้ในมุมมองเมื่อสร้างฟอร์ม โดยค่าเริ่มต้นการกระทำ new จะแสดงผล app/views/articles/new.html.erb ซึ่งเราจะสร้างต่อไป

การกระทำ create จะสร้างอินสแตนซ์ของบทความใหม่พร้อมค่าสำหรับชื่อเรื่องและเนื้อหา และพยายามบันทึกไว้ หากบทความถูกบันทึกเรียบร้อยแล้ว การกระทำจะเปลี่ยนเส้นทางเบราว์เซอร์ไปยังหน้าบทความที่ "http://localhost:3000/articles/#{@article.id}" หากไม่สำเร็จ การกระทำจะแสดงฟอร์มอีกครั้งโดยแสดงผล app/views/articles/new.html.erb พร้อมรหัสสถานะ 422 Unprocessable Entity ชื่อเรื่องและเนื้อหาที่นี่เป็นค่าเสมือน หลังจากที่เราสร้างฟอร์มเสร็จ เราจะกลับมาแก้ไขส่วนนี้

หมายเหตุ: redirect_to จะทำให้เบราว์เซอร์สร้างคำขอใหม่ ในขณะที่ render จะแสดงผลมุมมองที่ระบุสำหรับคำขอปัจจุบัน สำคัญที่จะใช้ redirect_to หลังจากเปลี่ยนแปลงฐานข้อมูลหรือสถานะแอปพลิเคชัน มิฉะนั้น หากผู้ใช้รีเฟรชหน้าเว็บ เบราว์เซอร์จะส่งคำขอเดียวกัน และการเปลี่ยนแปลงจะถูกทำซ้ำ

4.3.1 ใช้ฟอร์มบิลเดอร์

เราจะใช้คุณสมบัติของ Rails ที่เรียกว่า ฟอร์มบิลเดอร์ เพื่อสร้างฟอร์มของเรา โดยใช้ฟอร์มบิลเดอร์ เราสามารถเขียนโค้ดเพียงเล็กน้อยเพื่อสร้างฟอร์มที่กำหนดค่าและปฏิบัติตามความเป็นไปของ Rails

ให้สร้าง app/views/articles/new.html.erb ด้วยเนื้อหาดังต่อไปนี้:

<h1>New Article</h1>

<%= form_with model: @article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

เมธอด form_with เป็นเมธอดช่วยในการสร้างฟอร์มบิลเดอร์ เราเรียกใช้เมธอดเช่น label และ text_field บนฟอร์มบิลเดอร์เพื่อแสดงองค์ประกอบของฟอร์มที่เหมาะสม

ผลลัพธ์ที่ได้จากการเรียกใช้ form_with ของเราจะมีลักษณะดังนี้:

<form action="/articles" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="...">

  <div>
    <label for="article_title">Title</label><br>
    <input type="text" name="article[title]" id="article_title">
  </div>

  <div>
    <label for="article_body">Body</label><br>
    <textarea name="article[body]" id="article_body"></textarea>
  </div>

  <div>
    <input type="submit" name="commit" value="Create Article" data-disable-with="Create Article">
  </div>
</form>

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับฟอร์มบิลเดอร์ โปรดดูที่ Action View Form Helpers

4.3.2 ใช้พารามิเตอร์แข็งแกร่ง

ข้อมูลฟอร์มที่ส่งมาจะถูกเก็บใน params Hash พร้อมกับพารามิเตอร์เส้นทางที่ถูกจับไว้ ดังนั้น การกระทำ create สามารถเข้าถึงชื่อเรื่องที่ส่งมาผ่าน params[:article][:title] และเนื้อหาที่ส่งมาผ่าน params[:article][:body] เราสามารถส่งค่าเหล่านี้ไปยัง Article.new แต่นั่นจะยาวและอาจเกิดข้อผิดพลาดได้ และมันจะเลวร้ายขึ้นเมื่อเราเพิ่มฟิลด์เพิ่มเติม

แทนนั้น เราจะส่ง Hash เดียวที่มีค่าเหล่านั้น อย่างไรก็ตาม เราต้องระบุค่าที่อนุญาตใน Hash นั้นอยู่ มิฉะนั้น ผู้ใช้ที่มีเจตนาไม่ดีอาจส่งฟอร์มเพิ่มเติมและเขียนทับข้อมูลส่วนตัว ในความเป็นจริง หากเราส่ง params[:article] Hash ที่ไม่ผ่านการกรองโดยตรงไปยัง Article.new Rails จะเรียกข้อผิดพลาด ForbiddenAttributesError เพื่อแจ้งเตือนเราเกี่ยวกับปัญหานี้ ดังนั้นเราจะใช้คุณสมบัติของ Rails ที่เรียกว่า พารามิเตอร์แข็งแกร่ง เพื่อกรอง params คิดเหมือนการกำหนดประเภทแข็งแกร่งสำหรับ params ให้เราเพิ่มเมธอดเอกสารส่วนตัวด้านล่างใน app/controllers/articles_controller.rb ที่ชื่อว่า article_params ที่กรอง params และเราจะเปลี่ยน create เพื่อใช้เมธอดนี้:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Strong Parameters โปรดดู Action Controller Overview § Strong Parameters.

4.3.3 การตรวจสอบความถูกต้องและการแสดงข้อความผิดพลาด

เหมือนที่เราเห็น การสร้างทรัพยากรเป็นกระบวนการหลายขั้นตอน การจัดการข้อมูลผู้ใช้ที่ไม่ถูกต้องเป็นขั้นตอนหนึ่งของกระบวนการนั้น Rails มีคุณสมบัติที่เรียกว่า validations เพื่อช่วยให้เราจัดการข้อมูลผู้ใช้ที่ไม่ถูกต้อง การตรวจสอบความถูกต้องเป็นกฎที่ตรวจสอบก่อนที่จะบันทึกออบเจ็กต์โมเดล หากการตรวจสอบใด ๆ ล้มเหลวการบันทึกจะถูกยกเลิกและข้อความผิดพลาดที่เหมาะสมจะถูกเพิ่มในแอตทริบิวต์ errors ของออบเจ็กต์โมเดล

ให้เราเพิ่มการตรวจสอบความถูกต้องบางอย่างในโมเดลของเราใน app/models/article.rb:

class Article < ApplicationRecord
  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

การตรวจสอบความถูกต้องแรกเป็นการประกาศว่าค่า title ต้องมีค่าที่มีอยู่ โดยเนื่องจาก title เป็นสตริงนั่นหมายความว่าค่า title ต้องมีอย่างน้อยหนึ่งอักขระที่ไม่ใช่ช่องว่าง

การตรวจสอบความถูกต้องที่สองเป็นการประกาศว่าค่า body ต้องมีค่าที่มีอยู่เช่นกัน นอกจากนี้ยังประกาศว่าค่า body ต้องมีความยาวอย่างน้อย 10 อักขระ

หมายเหตุ: คุณอาจสงสัยว่าแอตทริบิวต์ title และ body ถูกกำหนดไว้ที่ไหน Active Record กำหนดแอตทริบิวต์โมเดลสำหรับทุกคอลัมน์ของตารางโดยอัตโนมัติดังนั้นคุณไม่ต้องประกาศแอตทริบิวต์เหล่านี้ในไฟล์โมเดลของคุณ

กับการตรวจสอบความถูกต้องที่เราได้กำหนดไว้ เราจะปรับเปลี่ยน app/views/articles/new.html.erb เพื่อแสดงข้อความผิดพลาดสำหรับ title และ body:

<h1>New Article</h1>

<%= form_with model: @article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
    <% @article.errors.full_messages_for(:title).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %><br>
    <% @article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

เมธอด full_messages_for จะคืนอาร์เรย์ของข้อความผิดพลาดที่เป็นมิตรกับผู้ใช้สำหรับแอตทริบิวต์ที่ระบุ หากไม่มีข้อผิดพลาดสำหรับแอตทริบิวต์นั้น อาร์เรย์จะเป็นว่างเปล่า

เพื่อให้เข้าใจว่าทุกอย่างทำงานร่วมกันอย่างไร ให้เรามองอีกครั้งที่การกระทำของคอนโทรลเลอร์ new และ create: ```ruby def new @article = Article.new end

def create @article = Article.new(article_params)

if @article.save
  redirect_to @article
else
  render :new, status: :unprocessable_entity
end

end ```

เมื่อเราเข้าถึง http://localhost:3000/articles/new คำขอ GET /articles/new จะถูกแมปไปยังแอ็กชัน new แอ็กชัน new ไม่พยายามบันทึก @article ดังนั้นการตรวจสอบความถูกต้องจะไม่ถูกตรวจสอบและจะไม่มีข้อความข้อผิดพลาด

เมื่อเราส่งแบบฟอร์ม คำขอ POST /articles จะถูกแมปไปยังแอ็กชัน create แอ็กชัน create พยายาม บันทึก @article ดังนั้นการตรวจสอบความถูกต้อง ถูกตรวจสอบ หากการตรวจสอบความถูกต้องล้มเหลว @article จะไม่ถูกบันทึกและ app/views/articles/new.html.erb จะถูกแสดงพร้อมกับข้อความข้อผิดพลาด

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการตรวจสอบความถูกต้อง ดูที่ Active Record Validations หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับข้อความข้อผิดพลาดจากการตรวจสอบความถูกต้อง ดูที่ Active Record Validations § การทำงานกับข้อผิดพลาดจากการตรวจสอบความถูกต้อง

4.3.4 การเสร็จสิ้น

เราสามารถสร้างบทความได้โดยเข้าถึง http://localhost:3000/articles/new เพื่อเสร็จสิ้น เราจะเชื่อมโยงไปยังหน้านั้นจากด้านล่างของ app/views/articles/index.html.erb:

<h1>บทความ</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= link_to article.title, article %>
    </li>
  <% end %>
</ul>

<%= link_to "บทความใหม่", new_article_path %>

4.4 การอัปเดตบทความ

เราได้พูดถึง "CR" ของ CRUD แล้ว ตอนนี้เรามาเรียนรู้เกี่ยวกับ "U" (อัปเดต) การอัปเดตทรัพยากรคล้ายกับการสร้างทรัพยากร ทั้งคู่เป็นกระบวนการหลายขั้นตอน ก่อนอื่นผู้ใช้จะขอแบบฟอร์มเพื่อแก้ไขข้อมูล จากนั้นผู้ใช้จะส่งแบบฟอร์ม หากไม่มีข้อผิดพลาด ทรัพยากรจะถูกอัปเดต มิฉะนั้น แบบฟอร์มจะถูกแสดงอีกครั้งพร้อมกับข้อความข้อผิดพลาดและกระบวนการจะถูกทำซ้ำ

ขั้นตอนเหล่านี้ถูกจัดการโดยแอ็กชัน edit และ update ของคอนโทรลเลอร์ตามปกติ มาเพิ่มการดำเนินการทั่วไปของแอ็กชันเหล่านี้ใน app/controllers/articles_controller.rb ด้านล่างของแอ็กชัน create:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  def edit
    @article = Article.find(params[:id])
  end

  def update
    @article = Article.find(params[:id])

    if @article.update(article_params)
      redirect_to @article
    else
      render :edit, status: :unprocessable_entity
    end
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

สังเกตว่าแอ็กชัน edit และ update คล้ายกับแอ็กชัน new และ create

แอ็กชัน edit ดึงบทความจากฐานข้อมูลและเก็บไว้ใน @article เพื่อใช้ในการสร้างแบบฟอร์ม โดยค่าเริ่มต้นแอ็กชัน edit จะแสดง app/views/articles/edit.html.erb

แอ็กชัน update ดึงบทความจากฐานข้อมูลอีกครั้งและพยายามอัปเดตด้วยข้อมูลแบบฟอร์มที่ส่งมาผ่าน article_params หากไม่มีการตรวจสอบความถูกต้องล้มเหลวและการอัปเดตสำเร็จแอ็กชันจะเปลี่ยนเส้นทางเบราว์เซอร์ไปยังหน้าบทความ มิฉะนั้นแอ็กชันจะแสดงแบบฟอร์มอีกครั้งพร้อมกับข้อความข้อผิดพลาด โดยการแสดง app/views/articles/edit.html.erb

4.4.1 การใช้ Partial เพื่อแบ่งปันโค้ดของ View

ฟอร์ม edit ของเราจะมีลักษณะเดียวกับฟอร์ม new ของเรา และโค้ดก็จะเหมือนกันเนื่องจากมี Rails form builder และ resourceful routing ช่วยให้โค้ดเหมือนกัน ฟอร์มบิลเดอร์จะกำหนดค่าฟอร์มให้เหมาะสมตามการร้องขอประเภทที่เหมาะสม ขึ้นอยู่กับว่าวัตถุโมเดลได้ถูกบันทึกไว้ก่อนหน้านี้หรือไม่

เนื่องจากโค้ดจะเหมือนกัน เราจะแยกออกเป็นส่วนย่อยที่เรียกว่า partial มาเก็บไว้ใน view ที่แชร์กัน โดยสร้างไฟล์ app/views/articles/_form.html.erb ด้วยเนื้อหาดังต่อไปนี้:

<%= form_with model: article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
    <% article.errors.full_messages_for(:title).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %><br>
    <% article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

โค้ดข้างต้นเหมือนกับฟอร์มใน app/views/articles/new.html.erb เพียงแต่ทุกครั้งที่พบ @article ถูกแทนที่ด้วย article โดย partial เป็นโค้ดที่แชร์กัน ดังนั้น สิ่งที่เป็นที่นิยมคือ partial ไม่ควรขึ้นอยู่กับตัวแปรอินสแตนซ์ที่ถูกกำหนดโดย controller action เราจะส่ง article เข้าไปใน partial เป็นตัวแปร local

ให้เราอัปเดต app/views/articles/new.html.erb เพื่อใช้ partial ผ่าน render:

<h1>บทความใหม่</h1>

<%= render "form", article: @article %>

หมายเหตุ: ชื่อไฟล์ของ partial ต้องมีเครื่องหมายขีดล่าง นำหน้า, เช่น _form.html.erb แต่เมื่อเรียกใช้ จะไม่ต้องใส่เครื่องหมายขีดล่าง เช่น render "form"

และตอนนี้ เราจะสร้าง app/views/articles/edit.html.erb ที่คล้ายกันมาก:

<h1>แก้ไขบทความ</h1>

<%= render "form", article: @article %>

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ partial ดูที่ Layouts and Rendering in Rails § Using Partials.

4.4.2 การจบงาน

เราสามารถอัปเดตบทความได้โดยเข้าไปที่หน้าแก้ไข ตัวอย่างเช่น http://localhost:3000/articles/1/edit เพื่อจบงาน เราจะเพิ่มลิงก์ไปยังหน้าแก้ไขจากด้านล่างของ app/views/articles/show.html.erb:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "แก้ไข", edit_article_path(@article) %></li>
</ul>

4.5 การลบบทความ

สุดท้าย เรามาถึง "D" (Delete) ของ CRUD การลบทรัพยากรง่ายกว่าการสร้างหรืออัปเดต มันต้องการเพียงเส้นทางเดียวกับการร้องขอและการกระทำของคอนโทรลเลอร์ และ resourceful routing (resources :articles) ที่เรามีอยู่แล้วจะให้เส้นทาง ซึ่งจะแมปการร้องขอ DELETE /articles/:id ไปยังการกระทำ destroy ของ ArticlesController

ดังนั้น เราจะเพิ่มการกระทำ destroy ทั่วไปใน app/controllers/articles_controller.rb ด้านล่างของการกระทำ update:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  def edit
    @article = Article.find(params[:id])
  end

  def update
    @article = Article.find(params[:id])

    if @article.update(article_params)
      redirect_to @article
    else
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @article = Article.find(params[:id])
    @article.destroy

    redirect_to root_path, status: :see_other
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

การกระทำ destroy จะดึงบทความจากฐานข้อมูลและเรียกใช้ destroy บนมัน จากนั้นจะเปลี่ยนเส้นทางของเบราว์เซอร์ไปยังเส้นทางหลักด้วยรหัสสถานะ 303 See Other.

เราได้เลือกเปลี่ยนเส้นทางไปยังเส้นทางหลักเนื่องจากเป็นจุดเข้าถึงหลักของบทความของเรา แต่ในสถานการณ์อื่น ๆ คุณอาจเลือกเปลี่ยนเส้นทางไปยังเช่น articles_path เป็นต้น

ตอนนี้เรามาเพิ่มลิงก์ที่ด้านล่างของ app/views/articles/show.html.erb เพื่อให้เราสามารถลบบทความจากหน้าของตัวเองได้:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= link_to "Destroy", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  } %></li>
</ul>

ในโค้ดด้านบน เราใช้ตัวเลือก data เพื่อตั้งค่าแอตทริบิวต์ HTML data-turbo-method และ data-turbo-confirm ของลิงก์ "Destroy" ทั้งสองแอตทริบิวต์นี้เชื่อมต่อกับ Turbo ซึ่งรวมอยู่ในแอปพลิเคชัน Rails ใหม่ๆ โดยค่าเริ่มต้น data-turbo-method="delete" จะทำให้ลิงก์ทำการร้องขอ DELETE แทนที่จะร้องขอ GET data-turbo-confirm="Are you sure?" จะทำให้ปรากฏกล่องโต้ตอบการยืนยันเมื่อคลิกลิงก์ หากผู้ใช้ยกเลิกกล่องโต้ตอบ การร้องขอจะถูกยกเลิก

และนั่นคือทั้งหมด! เราสามารถรายการบทความ แสดงรายละเอียดบทความ สร้าง แก้ไข และลบบทความได้แล้ว! InCRUDable!

5 การเพิ่มโมเดลที่สอง

ถึงเวลาที่จะเพิ่มโมเดลที่สองในแอปพลิเคชัน เป็นโมเดลที่สองที่จะจัดการความคิดเห็นในบทความ

5.1 การสร้างโมเดล

เราจะใช้เจเนอเรเตอร์เดียวกับที่เราใช้ก่อนหน้านี้เมื่อสร้างโมเดล Article ครั้งนี้เราจะสร้างโมเดล Comment เพื่อเก็บอ้างอิงไปยังบทความ ให้รันคำสั่งนี้ในเทอร์มินัลของคุณ:

$ bin/rails generate model Comment commenter:string body:text article:references

คำสั่งนี้จะสร้างไฟล์สี่ไฟล์:

ไฟล์ วัตถุประสงค์
db/migrate/20140120201010_create_comments.rb การโยกย้ายเพื่อสร้างตารางความคิดเห็นในฐานข้อมูลของคุณ (ชื่อของคุณจะรวมไปถึงการปรับเปลี่ยนเวลาที่แตกต่างกัน)
app/models/comment.rb โมเดล Comment
test/models/comment_test.rb เครื่องมือทดสอบสำหรับโมเดล Comment
test/fixtures/comments.yml ความคิดเห็นตัวอย่างสำหรับใช้ในการทดสอบ

ก่อนอื่น ลองดูที่ app/models/comment.rb:

class Comment < ApplicationRecord
  belongs_to :article
end

นี่คือคลาสโมเดล Comment ที่คล้ายกับโมเดล Article ที่คุณเห็นก่อนหน้านี้ ความแตกต่างคือบรรทัด belongs_to :article ซึ่งกำหนดการสร้าง association ของ Active Record คุณจะเรียนรู้เล็กน้อยเกี่ยวกับการสร้าง association ในส่วนถัดไปของเอกสารนี้

คำสำคัญ (:references) ที่ใช้ในคำสั่งเชลนี้เป็นชนิดข้อมูลพิเศษสำหรับโมเดล มันจะสร้างคอลัมน์ใหม่ในตารางฐานข้อมูลของคุณที่มีชื่อโมเดลที่ให้มาต่อท้ายด้วย _id ซึ่งสามารถเก็บค่าจำนวนเต็มได้ เพื่อให้เข้าใจได้ดีขึ้น วิเคราะห์ไฟล์ db/schema.rb หลังจากเรียกใช้การโยกย้าย นอกจากโมเดลแล้ว Rails ยังสร้างการเคลื่อนย้ายเพื่อสร้างตารางฐานข้อมูลที่เกี่ยวข้อง:

class CreateComments < ActiveRecord::Migration[7.0]
  def change
    create_table :comments do |t|
      t.string :commenter
      t.text :body
      t.references :article, null: false, foreign_key: true

      t.timestamps
    end
  end
end

บรรทัด t.references สร้างคอลัมน์ชนิด integer ที่ชื่อ article_id พร้อมดัชนีและข้อจำกัดความสัมพันธ์ที่ชี้ไปที่คอลัมน์ id ของตาราง articles ลองรันการเคลื่อนย้าย:

$ bin/rails db:migrate

Rails มีความสามารถในการเรียกใช้เฉพาะการเคลื่อนย้ายที่ยังไม่ได้รันกับฐานข้อมูลปัจจุบัน ดังนั้นในกรณีนี้คุณจะเห็นเพียง:

==  CreateComments: migrating =================================================
-- create_table(:comments)
   -> 0.0115s
==  CreateComments: migrated (0.0119s) ========================================

5.2 การเชื่อมโยงโมเดล

การเชื่อมโยง Active Record ช่วยให้คุณสามารถประกาศความสัมพันธ์ระหว่างโมเดลสองตัวได้ง่ายดาย ในกรณีของความคิดเห็นและบทความ คุณสามารถเขียนความสัมพันธ์ได้ดังนี้:

  • แต่ละความคิดเห็นเป็นส่วนหนึ่งของบทความหนึ่ง
  • บทความหนึ่งสามารถมีความคิดเห็นได้หลายอัน

ในความเป็นจริงนี้เป็นรูปแบบที่ใกล้เคียงกับไวยากรณ์ที่ Rails ใช้ในการประกาศความสัมพันธ์นี้ คุณเคยเห็นบรรทัดโค้ดภายในโมเดล Comment (app/models/comment.rb) ที่ทำให้แต่ละความคิดเห็นเป็นส่วนหนึ่งของบทความ:

class Comment < ApplicationRecord
  belongs_to :article
end

คุณจะต้องแก้ไข app/models/article.rb เพื่อเพิ่มส่วนอื่น ๆ ของความสัมพันธ์:

class Article < ApplicationRecord
  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

การประกาศสองส่วนนี้ช่วยให้มีพฤติกรรมอัตโนมัติได้มากมาย ตัวอย่างเช่นหากคุณมีตัวแปรอินสแตนซ์ @article ที่มีบทความ คุณสามารถเรียกดูความคิดเห็นทั้งหมดที่เกี่ยวข้องกับบทความนั้นในรูปแบบอาร์เรย์ได้โดยใช้ @article.comments.

เคล็ดลับ: สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเชื่อมโยง Active Record ดูที่ Active Record Associations guide.

5.3 เพิ่มเส้นทางสำหรับความคิดเห็น

เช่นเดียวกับควบคุมเรื่อง articles เราจะต้องเพิ่มเส้นทางเพื่อให้ Rails ทราบว่าเราต้องการไปยังไหนเพื่อดู comments เปิดไฟล์ config/routes.rb อีกครั้งและแก้ไขดังนี้:

Rails.application.routes.draw do
  root "articles#index"

  resources :articles do
    resources :comments
  end
end

สร้าง comments เป็น nested resource ภายใน articles นี้เป็นส่วนหนึ่งของการจับคู่ความสัมพันธ์ที่มีลำดับที่อยู่ระหว่างบทความและความคิดเห็น

เคล็ดลับ: สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเชื่อมต่อดูที่ Rails Routing guide.

5.4 การสร้างควบคุมเลเยอร์

ด้วยโมเดลที่มีอยู่แล้วคุณสามารถสร้างควบคุมเลเยอร์ที่เข้ากันได้ อีกครั้งเราจะใช้เครื่องมือเดียวกันที่เราใช้ก่อนหน้านี้: bash $ bin/rails generate controller Comments

นี้จะสร้างไฟล์สามไฟล์และไดเรกทอรีว่างเปล่าหนึ่ง:

ไฟล์/ไดเรกทอรี วัตถุประสงค์
app/controllers/comments_controller.rb Comments controller
app/views/comments/ จัดเก็บวิวของคอนโทรลเลอร์ที่นี่
test/controllers/comments_controller_test.rb ทดสอบคอนโทรลเลอร์
app/helpers/comments_helper.rb ไฟล์ช่วยเหลือในการแสดงผล

เช่นเดียวกับบล็อกใด ๆ ผู้อ่านของเราจะสร้างความคิดเห็นของตนโดยตรงหลังจากอ่านบทความและเมื่อเพิ่มความคิดเห็นของตนแล้วจะถูกส่งกลับไปที่หน้าแสดงบทความเพื่อดูความคิดเห็นของตนที่รายการแล้ว ด้วยเหตุนี้ CommentsController ของเราจึงมีการให้บริการเพื่อสร้างความคิดเห็นและลบความคิดเห็นสแปมเมื่อมันมาถึง

ดังนั้นก่อนอื่นเราจะเชื่อมต่อเทมเพลตแสดงบทความ (app/views/articles/show.html.erb) เพื่อให้เราสามารถสร้างความคิดเห็นใหม่ได้:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "แก้ไข", edit_article_path(@article) %></li>
  <li><%= link_to "ลบ", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "แน่ใจหรือไม่?"
                  } %></li>
</ul>

<h2>เพิ่มความคิดเห็น:(3)</h2>
<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

นี้เพิ่มฟอร์มในหน้าแสดง Article ที่สร้างความคิดเห็นใหม่โดยเรียกใช้การกระทำ create ของ CommentsController การเรียกใช้ form_with ที่นี่ใช้อาร์เรย์ซึ่งจะสร้างเส้นทางที่ซ้อนกัน เช่น /articles/1/comments

มาเชื่อมต่อ create ใน app/controllers/comments_controller.rb:

class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end

  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end

คุณจะเห็นความซับซ้อนเล็กน้อยที่นี่มากกว่าที่คุณเห็นในคอนโทรลเลอร์สำหรับบทความ นั่นเป็นผลข้างเคียงของการซ้อนที่คุณได้ตั้งค่า แต่ละคำขอสำหรับความคิดเห็นต้องติดตามบทความที่ความคิดเห็นแนบอยู่ ดังนั้นการเรียกใช้เมธอด find ของโมเดล Article เพื่อรับบทความที่สงสัย

นอกจากนี้โค้ดยังใช้ประโยชน์จากเมธอดบางอย่างที่มีอยู่สำหรับความสัมพันธ์ เราใช้เมธอด create บน @article.comments เพื่อสร้างและบันทึกความคิดเห็น นี้จะเชื่อมโยงความคิดเห็นโดยอัตโนมัติเพื่อให้เป็นส่วนหนึ่งของบทความนั้น

เมื่อเราทำความคิดเห็นใหม่แล้วเราจะส่งผู้ใช้กลับไปที่บทความเดิมโดยใช้ตัวช่วย article_path(@article) เหมือนที่เราเคยเห็น นี้เรียกใช้การกระทำ show ของ ArticlesController ซึ่งในเทมเพลต show.html.erb จะแสดงความคิดเห็น ดังนั้นเราจะเพิ่มส่วนนั้นใน app/views/articles/show.html.erb ```html+erb

<%= @article.title %>

<%= @article.body %>

  • <%= link_to "แก้ไข", edit_article_path(@article) %>
  • <%= link_to "ลบ", article_path(@article), data: { turbo_method: :delete, turbo_confirm: "คุณแน่ใจหรือไม่?" } %>

6 ความคิดเห็น1

<% @article.comments.each do |comment| %>

ผู้แสดงความคิดเห็น: <%= comment.commenter %>

ความคิดเห็น: <%= comment.body %>

<% end %>

7 เพิ่มความคิดเห็น:

<%= form_with model: [ @article, @article.comments.build ] do |form| %>

<%= form.label :commenter %>
<%= form.text_field :commenter %>

<%= form.label :body %>
<%= form.text_area :body %>

<%= form.submit %>

<% end %> ```

ตอนนี้คุณสามารถเพิ่มบทความและความคิดเห็นในบล็อกของคุณและมีการแสดงผลในตำแหน่งที่ถูกต้อง

บทความพร้อมความคิดเห็น

8 การรวมรูปแบบ

ตอนนี้ที่เรามีบทความและความคิดเห็นทำงานอยู่แล้ว ลองดูที่เทมเพลต app/views/articles/show.html.erb มันยาวและยุ่งเหยิง พวกเราสามารถใช้ partials เพื่อทำความสะอาด

8.1 การแสดงรวมของ Partial

ก่อนอื่น เราจะสร้าง partial สำหรับแสดงความคิดเห็นทั้งหมดในบทความ สร้างไฟล์ app/views/comments/_comment.html.erb และใส่โค้ดต่อไปนี้ลงไป:

<p>
  <strong>ผู้แสดงความคิดเห็น:</strong>
  <%= comment.commenter %>
</p>

<p>
  <strong>ความคิดเห็น:</strong>
  <%= comment.body %>
</p>

จากนั้นคุณสามารถเปลี่ยน app/views/articles/show.html.erb เป็นดังนี้:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "แก้ไข", edit_article_path(@article) %></li>
  <li><%= link_to "ลบ", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "คุณแน่ใจหรือไม่?"
                  } %></li>
</ul>

<h2>ความคิดเห็น3</h2>
<%= render @article.comments %>

<h2>เพิ่มความคิดเห็น:(1)</h2>
<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

ตอนนี้มันจะแสดง partial ใน app/views/comments/_comment.html.erb สำหรับแต่ละความคิดเห็นที่อยู่ในคอลเลกชัน @article.comments โดยเมื่อเรียกใช้เมธอด render จะทำการวนซ้ำผ่านคอลเลกชัน @article.comments และกำหนดค่าแต่ละความคิดเห็นให้เป็นตัวแปรโลคอลชื่อเดียวกับ partial ในที่นี้คือ comment ซึ่งจะสามารถใช้ใน partial เพื่อแสดงผลได้

8.2 การแสดงฟอร์ม Partial

เรายังสามารถย้ายส่วนของการเพิ่มความคิดเห็นใหม่ไปยัง partial ของตัวเองได้อีกด้วย อีกครั้ง คุณสร้างไฟล์ app/views/comments/_form.html.erb ที่มีโค้ดต่อไปนี้:

<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

จากนั้นคุณทำให้ app/views/articles/show.html.erb ดูเหมือนนี้: ```html+erb

<%= @article.title %>

<%= @article.body %>

  • <%= link_to "แก้ไข", edit_article_path(@article) %>
  • <%= link_to "ลบ", article_path(@article), data: { turbo_method: :delete, turbo_confirm: "คุณแน่ใจหรือไม่?" } %>

9 ความคิดเห็น2

<%= render @article.comments %>

10 เพิ่มความคิดเห็น:(2)

<%= render 'comments/form' %> ```

การ render ครั้งที่สองเพียงกำหนด template ย่อยที่เราต้องการ render คือ comments/form ระบบ Rails จะสามารถรู้ว่าเราต้องการ render ไฟล์ _form.html.erb ในโฟลเดอร์ app/views/comments ได้เอง

ออบเจ็กต์ @article สามารถใช้งานได้ใน partials ที่ render ใน view ได้เนื่องจากเรากำหนดให้เป็นตัวแปรอินสแตนซ์

10.1 การใช้ Concerns

Concerns เป็นวิธีที่ช่วยให้การจัดการและเข้าใจความหมายของ controller หรือ model ที่ใหญ่มากขึ้น นอกจากนี้ยังมีประโยชน์ในเรื่องการ reuse เมื่อมีการใช้งานของ model (หรือ controller) หลายๆ ตัวที่มี concerns เหมือนกัน การใช้งาน concerns จะใช้ module เหมือนกับการใช้งาน module ในภาษาอื่นๆ โดย module จะมี method ที่แสดงถึงฟังก์ชันที่กำหนดไว้ใน model หรือ controller ที่รับผิดชอบในส่วนที่กำหนดไว้ ในภาษาอื่นๆ โมดูลมักจะเรียกว่า mixins

คุณสามารถใช้ concerns ใน controller หรือ model ได้เหมือนกับการใช้งาน module ใดๆ ก่อนหน้านี้เมื่อคุณสร้างแอปพลิเคชันครั้งแรกด้วยคำสั่ง rails new blog โฟลเดอร์สองโฟลเดอร์ที่สร้างขึ้นใน app/ คือ:

app/controllers/concerns
app/models/concerns

ในตัวอย่างด้านล่าง เราจะนำเสนอฟีเจอร์ใหม่สำหรับบล็อกของเราที่จะได้รับประโยชน์จากการใช้งาน concerns จากนั้นเราจะสร้าง concerns และ refactor โค้ดให้ใช้งาน concerns เพื่อทำให้โค้ดสั้นลงและง่ายต่อการบำรุงรักษา

บทความบล็อกอาจมีสถานะต่างๆ เช่น อาจเป็นสถานะที่มองเห็นได้ทุกคน (เช่น public) หรือเป็นสถานะที่มองเห็นได้เฉพาะผู้เขียน (เช่น private) หรืออาจถูกซ่อนไม่ให้มองเห็น (เช่น archived) ความคิดเห็นอาจมีลักษณะเดียวกันเช่นกัน ซึ่งสามารถแสดงได้โดยใช้คอลัมน์ status ในแต่ละโมเดล

ก่อนอื่น เราจะรัน migration ต่อไปนี้เพื่อเพิ่ม status ใน Articles และ Comments:

$ bin/rails generate migration AddStatusToArticles status:string
$ bin/rails generate migration AddStatusToComments status:string

และต่อมา เราจะอัปเดตฐานข้อมูลด้วย migration ที่สร้างขึ้น:

$ bin/rails db:migrate

ในการเลือกสถานะสำหรับบทความและความคิดเห็นที่มีอยู่ คุณสามารถเพิ่มค่าเริ่มต้นให้กับไฟล์ migration ที่สร้างขึ้นโดยเพิ่ม default: "public" และรัน migration อีกครั้ง คุณยังสามารถเรียกใช้ Article.update_all(status: "public") และ Comment.update_all(status: "public") ในระหว่างการทำงานใน rails console ได้

เคล็ดลับ: หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ migrations โปรดดูที่ Active Record Migrations. `` เรายังต้องอนุญาตให้คีย์:statusเป็นส่วนหนึ่งของพารามิเตอร์ที่เข้มงวดในapp/controllers/articles_controller.rb`:


  private
    def article_params
      params.require(:article).permit(:title, :body, :status)
    end

และใน app/controllers/comments_controller.rb:


  private
    def comment_params
      params.require(:comment).permit(:commenter, :body, :status)
    end

ภายในโมเดล article หลังจากเรียกใช้การโยกย้ายเพื่อเพิ่มคอลัมน์ status โดยใช้คำสั่ง bin/rails db:migrate คุณจะเพิ่ม:

class Article < ApplicationRecord
  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }

  VALID_STATUSES = ['public', 'private', 'archived']

  validates :status, inclusion: { in: VALID_STATUSES }

  def archived?
    status == 'archived'
  end
end

และในโมเดล Comment:

class Comment < ApplicationRecord
  belongs_to :article

  VALID_STATUSES = ['public', 'private', 'archived']

  validates :status, inclusion: { in: VALID_STATUSES }

  def archived?
    status == 'archived'
  end
end

จากนั้นในแม่แบบการกระทำ index (app/views/articles/index.html.erb) เราจะใช้เมธอด archived? เพื่อหลีกเลี่ยงการแสดงบทความที่ถูกเก็บถาวร:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <% unless article.archived? %>
      <li>
        <%= link_to article.title, article %>
      </li>
    <% end %>
  <% end %>
</ul>

<%= link_to "New Article", new_article_path %>

ในทางเดียวกัน ในมุมมองส่วนหนึ่งของความคิด (app/views/comments/_comment.html.erb) เราจะใช้เมธอด archived? เพื่อหลีกเลี่ยงการแสดงความคิดเห็นที่ถูกเก็บถาวร:

<% unless comment.archived? %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
  </p>

  <p>
    <strong>Comment:</strong>
    <%= comment.body %>
  </p>
<% end %>

อย่างไรก็ตาม หากคุณมองอีกครั้งที่โมเดลของเราตอนนี้ คุณจะเห็นว่าตรรกะซ้ำกัน หากในอนาคตเราเพิ่มฟังก์ชันการทำงานของบล็อกของเรา - เช่นการรวมข้อความส่วนตัว - เราอาจพบว่าตรรกะซ้ำกันอีกครั้ง นี่คือสิ่งที่ความกังวลมาช่วยเรา

ความกังวลเป็นเพียงความรับผิดชอบเฉพาะสำหรับส่วนย่อยที่เกี่ยวข้องกับความสามารถในการมองเห็นของโมเดล ให้เราเรียกความกังวลใหม่ของเรา (โมดูล) Visible เราสามารถสร้างไฟล์ใหม่ภายใน app/models/concerns ที่เรียกว่า visible.rb และเก็บเมธอดทั้งหมดที่เกี่ยวข้องกับสถานะที่ซ้ำกันในโมเดล

app/models/concerns/visible.rb

module Visible
  def archived?
    status == 'archived'
  end
end

เราสามารถเพิ่มการตรวจสอบสถานะในความกังวล แต่นี้จะซับซ้อนขึ้นเล็กน้อยเนื่องจากการตรวจสอบคือเมธอดที่เรียกใช้ในระดับคลาส ActiveSupport::Concern (API Guide) ให้เราวิธีที่ง่ายกว่าในการรวมมัน:

module Visible
  extend ActiveSupport::Concern

  VALID_STATUSES = ['public', 'private', 'archived']

  included do
    validates :status, inclusion: { in: VALID_STATUSES }
  end

  def archived?
    status == 'archived'
  end
end

ตอนนี้เราสามารถลบโลจิกที่ซ้ำกันออกจากแต่ละโมเดลและแทนที่ด้วยโมดูล Visible ใหม่ของเราได้:

ใน app/models/article.rb:

class Article < ApplicationRecord
  include Visible

  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

และใน app/models/comment.rb:

class Comment < ApplicationRecord
  include Visible

  belongs_to :article
end

เมธอดคลาสก็สามารถเพิ่มในความสนใจได้ หากเราต้องการแสดงจำนวนบทความหรือความคิดเห็นสาธารณะบนหน้าหลักของเรา เราอาจเพิ่มเมธอดคลาสไปยัง Visible ดังนี้:

module Visible
  extend ActiveSupport::Concern

  VALID_STATUSES = ['public', 'private', 'archived']

  included do
    validates :status, inclusion: { in: VALID_STATUSES }
  end

  class_methods do
    def public_count
      where(status: 'public').count
    end
  end

  def archived?
    status == 'archived'
  end
end

จากนั้นในมุมมอง เราสามารถเรียกใช้ได้เหมือนเมธอดคลาสอื่น ๆ:

<h1>บทความ</h1>

บล็อกของเรามีบทความ <%= Article.public_count %> บทความและกำลังเพิ่มขึ้น!

<ul>
  <% @articles.each do |article| %>
    <% unless article.archived? %>
      <li>
        <%= link_to article.title, article %>
      </li>
    <% end %>
  <% end %>
</ul>

<%= link_to "บทความใหม่", new_article_path %>

เพื่อจบการทำงาน เราจะเพิ่มกล่องเลือกในฟอร์มและให้ผู้ใช้เลือกสถานะเมื่อสร้างบทความใหม่หรือโพสต์ความคิดเห็นใหม่ เรายังสามารถระบุสถานะเริ่มต้นเป็น public ได้ด้วย ใน app/views/articles/_form.html.erb เราสามารถเพิ่มได้:

<div>
  <%= form.label :status %><br>
  <%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</div>

และใน app/views/comments/_form.html.erb:

<p>
  <%= form.label :status %><br>
  <%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</p>

11 การลบความคิดเห็น

คุณลักษณะอีกอย่างที่สำคัญของบล็อกคือการลบความคิดเห็นสแปม ในการทำ นี้ เราต้องการสร้างลิงก์ในมุมมองและการกระทำ destroy ใน CommentsController

ดังนั้นก่อนอื่น เราจะเพิ่มลิงก์ลบในส่วน app/views/comments/_comment.html.erb:

<% unless comment.archived? %>
  <p>
    <strong>ผู้แสดงความคิดเห็น:</strong>
    <%= comment.commenter %>
  </p>

  <p>
    <strong>ความคิดเห็น:</strong>
    <%= comment.body %>
  </p>

  <p>
    <%= link_to "ลบความคิดเห็น", [comment.article, comment], data: {
                  turbo_method: :delete,
                  turbo_confirm: "แน่ใจหรือไม่?"
                } %>
  </p>
<% end %>

การคลิกลิงก์ "ลบความคิดเห็น" ใหม่นี้จะเรียกใช้ DELETE /articles/:article_id/comments/:id ไปยัง CommentsController ของเรา ซึ่งจะใช้สิ่งนี้ในการค้นหาความคิดเห็นที่เราต้องการลบ ดังนั้นเราจะเพิ่มการกระทำ destroy ในคอนโทรลเลอร์ (app/controllers/comments_controller.rb):

class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end

  def destroy
    @article = Article.find(params[:article_id])
    @comment = @article.comments.find(params[:id])
    @comment.destroy
    redirect_to article_path(@article), status: :see_other
  end

  private
    def comment_params
      params.require(:comment).permit(:commenter, :body, :status)
    end
end

การกระทำ destroy จะค้นหาบทความที่เรากำลังมองหา และค้นหาความคิดเห็นภายในคอลเลกชัน @article.comments จากนั้นจึงลบออกจากฐานข้อมูลและส่งกลับไปที่การกระทำ show สำหรับบทความ

11.1 การลบวัตถุที่เกี่ยวข้อง

หากคุณลบบทความ ความคิดเห็นที่เกี่ยวข้องก็จะต้องถูกลบด้วย มิฉะนั้นมันจะเพียงแค่ใช้พื้นที่ในฐานข้อมูล Rails ช่วยให้คุณสามารถใช้ตัวเลือก dependent ของการเชื่อมโยงเพื่อทำสิ่งนี้ได้ แก้ไขโมเดล Article app/models/article.rb ดังนี้:

class Article < ApplicationRecord
  include Visible

  has_many :comments, dependent: :destroy

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

12 ความปลอดภัย

12.1 การรับรองความถูกต้องขั้นพื้นฐาน

หากคุณต้องการเผยแพร่บล็อกของคุณออนไลน์ ใครก็สามารถเพิ่ม แก้ไข และลบบทความหรือลบความคิดเห็นได้

Rails มีระบบการรับรองความถูกต้องขั้นพื้นฐานที่จะทำงานได้ดีในสถานการณ์นี้

ใน ArticlesController เราต้องมีวิธีการบล็อกการเข้าถึงการกระทำต่าง ๆ หากบุคคลไม่ได้รับการรับรองความถูกต้อง ที่นี่เราสามารถใช้วิธี http_basic_authenticate_with ของ Rails ซึ่งอนุญาตให้เข้าถึงการกระทำที่ร้องขอได้หากวิธีนั้นอนุญาตให้เข้าถึง

ในการใช้ระบบการรับรองความถูกต้อง เราระบุให้มันที่ด้านบนของ ArticlesController ใน app/controllers/articles_controller.rb ในกรณีของเรา เราต้องการให้ผู้ใช้รับรองความถูกต้องในทุก ๆ การกระทำยกเว้น index และ show เราเขียนดังนี้:

class ArticlesController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]

  def index
    @articles = Article.all
  end

  # โค้ดส่วนที่เหลือเพื่อความกระชับ

เรายังต้องการให้เฉพาะผู้ใช้ที่รับรองความถูกต้องเท่านั้นที่สามารถลบความคิดเห็นได้ ดังนั้นใน CommentsController (app/controllers/comments_controller.rb) เราเขียนดังนี้:

class CommentsController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy

  def create
    @article = Article.find(params[:article_id])
    # ...
  end

  # โค้ดส่วนที่เหลือเพื่อความกระชับ

ตอนนี้หากคุณพยายามสร้างบทความใหม่ คุณจะได้รับการทดสอบการรับรองความถูกต้อง HTTP พื้นฐาน:

Basic HTTP Authentication Challenge

หลังจากใส่ชื่อผู้ใช้และรหัสผ่านที่ถูกต้อง คุณจะยังคงได้รับการรับรองความถูกต้องจนกว่าจะต้องการชื่อผู้ใช้และรหัสผ่านที่แตกต่างหรือปิดเบราว์เซอร์

วิธีการรับรองความถูกต้องอื่น ๆ สามารถใช้ได้สำหรับแอปพลิเคชัน Rails มีเครื่องมือรับรองความถูกต้องสองตัวที่นิยมคือ Devise และ Authlogic รวมถึงอื่น ๆ อีกหลายตัว

12.2 ข้อคิดอื่น ๆ เกี่ยวกับความปลอดภัย

ความปลอดภัย โดยเฉพาะในแอปพลิเคชันเว็บ เป็นเรื่องที่กว้างขวางและละเอียดอ่อน ความปลอดภัยในแอปพลิเคชัน Rails ของคุณจะถูกครอบคลุมอย่างละเอียดมากขึ้นใน คู่มือความปลอดภัยของ Ruby on Rails

13 สิ่งที่ต่อไป?

ตอนนี้ที่คุณได้เห็นแอปพลิเคชัน Rails ครั้งแรกของคุณแล้ว คุณสามารถอัปเดตและทดลองด้วยตัวเองได้เลย

อย่าลืมว่าคุณไม่ต้องทำทุกอย่างด้วยตัวเอง หากคุณต้องการความช่วยเหลือในการเริ่มต้นและใช้งาน Rails คุณสามารถเรียกดูทรัพยากรการสนับสนุนเหล่านี้ได้:

14 การตั้งค่าที่ควรระวัง

วิธีที่ง่ายที่สุดในการทำงานกับ Rails คือการเก็บข้อมูลภายนอกทั้งหมดในรูปแบบ UTF-8 หากคุณไม่ทำเช่นนั้น ไลบรารีของ Ruby และ Rails บางครั้งอาจสามารถแปลงข้อมูลภาษาในรูปแบบเดิมของคุณเป็น UTF-8 ได้ แต่นี่ไม่ได้ทำงานอย่างเสถียรเสมอ ดังนั้นคุณควรให้แน่ใจว่าข้อมูลภายนอกทั้งหมดเป็น UTF-8

หากคุณทำผิดพลาดในส่วนนี้ อาการที่พบบ่อยที่สุดคือมีสัญลักษณ์เพชรสีดำที่มีเครื่องหมายคำถามอยู่ภายในปรากฏในเบราว์เซอร์ อาการที่พบบ่อยอื่น ๆ คือตัวอักษรเช่น "ü" ปรากฏแทน "ü" Rails มีขั้นตอนภายในหลายอย่างเพื่อลดปัญหาที่เกิดขึ้นบ่อยๆ เช่นนี้ที่อาจตรวจจับและแก้ไขได้โดยอัตโนมัติ อย่างไรก็ตามหากคุณมีข้อมูลภายนอกที่ไม่ได้เก็บเป็น UTF-8 อาจทำให้เกิดปัญหาเช่นนี้ที่ Rails ไม่สามารถตรวจจับและแก้ไขได้อัตโนมัติ

แหล่งข้อมูลสองแห่งที่พบบ่อยที่ไม่ใช่ UTF-8:

  • ตัวแก้ไขข้อความของคุณ: ส่วนใหญ่ตัวแก้ไขข้อความ (เช่น TextMate) จะตั้งค่าเริ่มต้นให้บันทึกไฟล์เป็น UTF-8 หากตัวแก้ไขข้อความของคุณไม่ได้ทำเช่นนั้น อาจทำให้ตัวอักษรพิเศษที่คุณป้อนในเทมเพลต (เช่น é) ปรากฏเป็นเพชรที่มีเครื่องหมายคำถามอยู่ในเบราว์เซอร์ สิ่งเดียวกันนี้ยังใช้กับไฟล์แปลภาษา i18n ของคุณ ตัวแก้ไขที่ไม่ได้ตั้งค่าเริ่มต้นเป็น UTF-8 (เช่นเวอร์ชันบางรุ่นของ Dreamweaver) มีวิธีเปลี่ยนค่าเริ่มต้นเป็น UTF-8 ให้ทำเช่นนั้น
  • ฐานข้อมูลของคุณ: Rails มีค่าเริ่มต้นในการแปลงข้อมูลจากฐานข้อมูลของคุณเป็น UTF-8 ที่ขอบเขต อย่างไรก็ตามหากฐานข้อมูลของคุณไม่ใช้ UTF-8 เป็นรูปแบบภายใน อาจไม่สามารถเก็บตัวอักษรที่ผู้ใช้ป้อนได้ทั้งหมด เช่นหากฐานข้อมูลของคุณใช้ Latin-1 เป็นรูปแบบภายใน และผู้ใช้ป้อนตัวอักษรรัสเซีย ฮิบรู หรือญี่ปุ่น ข้อมูลจะหายไปตลอดไปเมื่อเข้าสู่ฐานข้อมูล หากเป็นไปได้ โปรดใช้ UTF-8 เป็นการเก็บข้อมูลภายในฐานข้อมูลของคุณ

ข้อเสนอแนะ

คุณสามารถช่วยปรับปรุงคุณภาพของคู่มือนี้ได้

กรุณาช่วยเพิ่มเติมหากพบข้อผิดพลาดหรือข้อผิดพลาดทางความจริง เพื่อเริ่มต้นคุณสามารถอ่านส่วน การสนับสนุนเอกสาร ของเราได้

คุณอาจพบเนื้อหาที่ไม่สมบูรณ์หรือเนื้อหาที่ไม่ได้อัปเดต กรุณาเพิ่มเอกสารที่ขาดหายไปสำหรับเนื้อหาหลัก โปรดตรวจสอบ Edge Guides ก่อนเพื่อตรวจสอบ ว่าปัญหาได้รับการแก้ไขหรือไม่ในสาขาหลัก ตรวจสอบ คู่มือแนวทาง Ruby on Rails เพื่อดูรูปแบบและกฎเกณฑ์

หากคุณพบข้อผิดพลาดแต่ไม่สามารถแก้ไขได้เอง กรุณา เปิดปัญหา.

และสุดท้าย การสนทนาใด ๆ เกี่ยวกับ Ruby on Rails เอกสารยินดีต้อนรับที่สุดใน เว็บบอร์ดอย่างเป็นทางการของ Ruby on Rails.