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

การตรวจสอบความถูกต้องของ Active Record

เอกสารนี้สอนคุณวิธีการตรวจสอบสถานะของอ็อบเจกต์ก่อนที่จะเข้าสู่ฐานข้อมูลโดยใช้คุณสมบัติการตรวจสอบของ Active Record

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

Chapters

  1. ภาพรวมของการตรวจสอบ
  2. ช่วยในการตรวจสอบความถูกต้อง
  3. Common Validation Options
  4. Strict Validations
  5. การตรวจสอบเงื่อนไข
  6. การจัดกลุ่มการตรวจสอบเงื่อนไข
  7. การทำการตรวจสอบที่กำหนดเอง
  8. การทำงานกับ Validation Errors
  9. แสดงข้อผิดพลาดการตรวจสอบในมุมมอง

1 ภาพรวมของการตรวจสอบ

นี่คือตัวอย่างของการตรวจสอบที่ง่ายมาก:

class Person < ApplicationRecord
  validates :name, presence: true
end
irb> Person.create(name: "John Doe").valid?
=> true
irb> Person.create(name: nil).valid?
=> false

จากตัวอย่างเราสามารถเห็นได้ว่าการตรวจสอบของเราบอกให้เราทราบว่า Person ของเราไม่ถูกต้องโดยไม่มีแอตทริบิวต์ name อันที่สอง Person จะไม่ถูกบันทึกลงในฐานข้อมูล

ก่อนที่เราจะลงรายละเอียดเพิ่มเติมเรามาพูดถึงว่าการตรวจสอบเข้ากับภาพรวมของแอปพลิเคชันของคุณอย่างไร

1.1 ทำไมต้องใช้การตรวจสอบ?

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

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

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

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

เลือกใช้เหล่านี้ในกรณีที่เฉพาะเจาะจงบางกรณี ทีม Rails เชื่อว่าการตรวจสอบระดับโมเดลเป็นวิธีที่เหมาะสมที่สุดในสถานการณ์ส่วนใหญ่

1.2 เมื่อใดที่การตรวจสอบเกิดขึ้น?

มีออบเจกต์ Active Record 2 ประเภท: ออบเจกต์ที่สอดคล้องกับแถวในฐานข้อมูลของคุณและออบเจกต์ที่ไม่สอดคล้องกับแถวในฐานข้อมูลของคุณ เมื่อคุณสร้างออบเจกต์ใหม่ เช่น โดยใช้เมธอด new ออบเจกต์นั้นยังไม่ได้เป็นส่วนหนึ่งของฐานข้อมูล หลังจากคุณเรียกใช้ save บนออบเจกต์นั้น มันจะถูกบันทึกลงในตารางฐานข้อมูลที่เหมาะสม Active Record ใช้เมธอด new_record? เพื่อตรวจสอบว่าออบเจกต์นั้นอยู่ในฐานข้อมูลแล้วหรือไม่ พิจารณาคลาส Active Record ต่อไปนี้: ruby class Person < ApplicationRecord end

เราสามารถดูวิธีการทำงานของมันได้โดยดูผลลัพธ์ของ bin/rails console:

irb> p = Person.new(name: "John Doe")
=> #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil>

irb> p.new_record?
=> true

irb> p.save
=> true

irb> p.new_record?
=> false

การสร้างและบันทึกบันทึกใหม่จะส่งคำสั่ง SQL INSERT ไปยังฐานข้อมูล การอัปเดตบันทึกที่มีอยู่จะส่งคำสั่ง SQL UPDATE แทน การตรวจสอบความถูกต้องทั่วไปจะถูกเรียกใช้ก่อนที่จะส่งคำสั่งเหล่านี้ไปยังฐานข้อมูล หากการตรวจสอบความถูกต้องล้มเหลว วัตถุนั้นจะถูกทำเครื่องหมายว่าไม่ถูกต้องและ Active Record จะไม่ดำเนินการ INSERT หรือ UPDATE นี้ เพื่อป้องกันการเก็บวัตถุที่ไม่ถูกต้องในฐานข้อมูล คุณสามารถเลือกให้การตรวจสอบความถูกต้องเฉพาะเกิดขึ้นเมื่อวัตถุถูกสร้าง บันทึก หรืออัปเดต

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

วิธีการต่อไปนี้จะเรียกใช้การตรวจสอบความถูกต้องและจะบันทึกวัตถุในฐานข้อมูลเฉพาะเมื่อวัตถุถูกต้อง:

  • create
  • create!
  • save
  • save!
  • update
  • update!

เวอร์ชันแบง (เช่น save!) จะเรียกข้อยกเว้นหากบันทึกไม่ถูกต้อง เวอร์ชันที่ไม่ใช่แบงไม่ได้: save และ update จะส่งค่า false และ create จะส่งวัตถุ

1.3 การข้ามการตรวจสอบความถูกต้อง

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

  • decrement!
  • decrement_counter
  • increment!
  • increment_counter
  • insert
  • insert!
  • insert_all
  • insert_all!
  • toggle!
  • touch
  • touch_all
  • update_all
  • update_attribute
  • update_column
  • update_columns
  • update_counters
  • upsert
  • upsert_all

โปรดทราบว่า save ยังสามารถข้ามการตรวจสอบความถูกต้องได้หากส่ง validate: false เป็นอาร์กิวเมนต์ วิธีนี้ควรใช้ด้วยความระมัดระวัง

  • save(validate: false)

1.4 valid? และ invalid?

ก่อนที่จะบันทึกวัตถุ Active Record เราจะเรียกใช้การตรวจสอบความถูกต้องของคุณ หากการตรวจสอบความถูกต้องนี้สร้างข้อผิดพลาดใด ๆ Rails จะไม่บันทึกวัตถุ

คุณยังสามารถเรียกใช้การตรวจสอบความถูกต้องเหล่านี้เอง valid? เรียกใช้การตรวจสอบความถูกต้องของคุณ และคืนค่า true หากไม่พบข้อผิดพลาดใด ๆ ในวัตถุ และ false ในทางกลับกัน เช่นเห็นได้จากตัวอย่างด้านบน:

class Person < ApplicationRecord
  validates :name, presence: true
end
irb> Person.create(name: "John Doe").valid?
=> true
irb> Person.create(name: nil).valid?
=> false

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

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

class Person < ApplicationRecord
  validates :name, presence: true
end
irb> p = Person.new
=> #<Person id: nil, name: nil>
irb> p.errors.size
=> 0

irb> p.valid?
=> false
irb> p.errors.objects.first.full_message
=> "Name can’t be blank"

irb> p = Person.create
=> #<Person id: nil, name: nil>
irb> p.errors.objects.first.full_message
=> "Name can’t be blank"

irb> p.save
=> false

irb> p.save!
ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank

irb> Person.create!
ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank

invalid? เป็นการสลับกันของ valid? มันจะเรียกใช้การตรวจสอบความถูกต้องของคุณลักษณะต่าง ๆ ในวัตถุ และคืนค่าเป็นจริงถ้าพบข้อผิดพลาดใด ๆ ในวัตถุ และเป็นเท็จในทางกลับกัน

1.5 errors[]

เพื่อตรวจสอบว่าคุณลักษณะใดของวัตถุนั้นถูกต้องหรือไม่ คุณสามารถใช้ errors[:attribute] ได้ มันจะคืนค่าเป็นอาร์เรย์ของข้อความผิดพลาดทั้งหมดสำหรับ :attribute หากไม่มีข้อผิดพลาดในคุณลักษณะที่ระบุ มันจะคืนค่าเป็นอาร์เรย์ว่าง

เมธอดนี้มีประโยชน์เฉพาะหลังจากที่การตรวจสอบความถูกต้องได้รันแล้ว เนื่องจากมันจะตรวจสอบเฉพาะคอลเลกชันของข้อผิดพลาดเท่านั้นและไม่เรียกใช้การตรวจสอบความถูกต้องเอง มันแตกต่างจากเมธอด ActiveRecord::Base#invalid? ที่อธิบายไว้ข้างต้น เนื่องจากมันไม่ตรวจสอบความถูกต้องของวัตถุในทั้งหมด มันเช็คเพียงเพื่อดูว่ามีข้อผิดพลาดที่พบในคุณลักษณะบุคคลของวัตถุหรือไม่

class Person < ApplicationRecord
  validates :name, presence: true
end
irb> Person.new.errors[:name].any?
=> false
irb> Person.create.errors[:name].any?
=> true

เราจะพูดถึงข้อผิดพลาดในการตรวจสอบอย่างละเอียดมากขึ้นในส่วน การทำงานกับข้อผิดพลาดในการตรวจสอบ

2 ช่วยในการตรวจสอบความถูกต้อง

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

แต่ละเครื่องมือยอมรับชื่อคุณลักษณะได้ไม่จำกัด ดังนั้นคุณสามารถเพิ่มการตรวจสอบประเภทเดียวกันไปยังคุณลักษณะหลาย ๆ คุณลักษณะได้ด้วยบรรทัดเดียว

ทุกเครื่องมือยอมรับตัวเลือก :on และ :message ซึ่งกำหนดเมื่อการตรวจสอบความถูกต้องควรทำงานและข้อความที่ควรเพิ่มในคอลเลกชัน errors หากการตรวจสอบล้มเหลวตามลำดับ ตัวเลือก :on รับค่าหนึ่งในค่า :create หรือ :update มีข้อความผิดพลาดเริ่มต้นสำหรับเครื่องมือตรวจสอบแต่ละอัน ข้อความเหล่านี้ถูกใช้เมื่อไม่ระบุตัวเลือก :message มาดูทีละเครื่องมือที่มีอยู่

หากต้องการดูรายการเครื่องมือช่วยเริ่มต้นที่มีอยู่ ดูที่ ActiveModel::Validations::HelperMethods

2.1 acceptance

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

class Person < ApplicationRecord
  validates :terms_of_service, acceptance: true
end

การตรวจสอบนี้จะถูกดำเนินการเฉพาะเมื่อ terms_of_service ไม่เป็น nil ข้อความผิดพลาดเริ่มต้นสำหรับเครื่องมือช่วยนี้คือ "ต้องยอมรับ" คุณยังสามารถส่งข้อความที่กำหนดเองผ่านตัวเลือก message

class Person < ApplicationRecord
  validates :terms_of_service, acceptance: { message: 'ต้องปฏิบัติตาม' }
end

มันยังสามารถรับตัวเลือก :accept ซึ่งกำหนดค่าที่ยอมรับที่จะถือว่าถูกต้อง มันเริ่มต้นเป็น ['1', true] และสามารถเปลี่ยนแปลงได้ง่าย

class Person < ApplicationRecord
  validates :terms_of_service, acceptance: { accept: 'yes' }
  validates :eula, acceptance: { accept: ['TRUE', 'accepted'] }
end

การตรวจสอบนี้เป็นเฉพาะในเว็บแอปพลิเคชันและ 'การยอมรับ' นี้ไม่จำเป็นต้องบันทึกไว้ในฐานข้อมูลของคุณ หากคุณไม่มีฟิลด์สำหรับมัน เครื่องมือช่วยจะสร้างคุณลักษณะเสมือน หากฟิลด์มีอยู่ในฐานข้อมูลของคุณ ตัวเลือก accept ต้องถูกตั้งค่าเป็นหรือรวม true มิฉะนั้นการตรวจสอบจะไม่ทำงาน

2.2 การยืนยัน

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

class Person < ApplicationRecord
  validates :email, confirmation: true
end

ในเทมเพลตของมุมมองของคุณ คุณสามารถใช้สิ่งที่คล้ายกันเช่น

<%= text_field :person, :email %>
<%= text_field :person, :email_confirmation %>

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

class Person < ApplicationRecord
  validates :email, confirmation: true
  validates :email_confirmation, presence: true
end

ยังมีตัวเลือก :case_sensitive ที่คุณสามารถใช้เพื่อกำหนดว่าการจำกัดการยืนยันจะเป็นตัวอักษรตัวใหญ่และตัวเล็กหรือไม่ ตัวเลือกนี้มีค่าเริ่มต้นเป็นจริง

class Person < ApplicationRecord
  validates :email, confirmation: { case_sensitive: false }
end

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

โดยทั่วไปเมื่อใช้ตัวตรวจสอบนี้ คุณต้องการรวมกับตัวเลือก :if เพื่อตรวจสอบเฉพาะฟิลด์ "_confirmation" เมื่อฟิลด์เริ่มต้นเปลี่ยนแปลงและ ไม่ทุกครั้งที่คุณบันทึกบันทึก อ่านเพิ่มเติมเกี่ยวกับ การตรวจสอบเงื่อนไข ในภายหลัง

class Person < ApplicationRecord
  validates :email, confirmation: true
  validates :email_confirmation, presence: true, if: :email_changed?
end

2.3 การเปรียบเทียบ

การตรวจสอบนี้จะตรวจสอบการเปรียบเทียบระหว่างค่าสองค่าที่เปรียบเทียบได้

class Promotion < ApplicationRecord
  validates :end_date, comparison: { greater_than: :start_date }
end

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

ตัวเลือกเหล่านี้ถูกสนับสนุนทั้งหมด:

  • :greater_than - ระบุว่าค่าต้องมากกว่าค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องมากกว่า %{count}"
  • :greater_than_or_equal_to - ระบุว่าค่าต้องมากกว่าหรือเท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องมากกว่าหรือเท่ากับ %{count}"
  • :equal_to - ระบุว่าค่าต้องเท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องเท่ากับ %{count}"
  • :less_than - ระบุว่าค่าต้องน้อยกว่าค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องน้อยกว่า %{count}"
  • :less_than_or_equal_to - ระบุว่าค่าต้องน้อยกว่าหรือเท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องน้อยกว่าหรือเท่ากับ %{count}"
  • :other_than - ระบุว่าค่าต้องไม่เท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องไม่เท่ากับ %{count}"

หมายเหตุ: ตัวตรวจสอบต้องการการเปรียบเทียบที่จะให้มีการระบุตัวเลือก แต่ละตัวเลือกยอมรับค่า โปรแกรม หรือสัญลักษณ์ ค่าใดก็ได้ คลาสใดก็ได้ที่รวม Comparable สามารถเปรียบเทียบกันได้

2.4 รูปแบบ

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

class Product < ApplicationRecord
  validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,
    message: "อนุญาตเฉพาะตัวอักษรเท่านั้น" }
end

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

ในทั้งสองกรณี ตัวเลือก :with หรือ :without ที่ให้มาต้องเป็น regular expression หรือ proc หรือ lambda ที่ส่งคืน regular expression

ข้อความข้อผิดพลาดเริ่มต้นคือ "ไม่ถูกต้อง"

คำเตือน ใช้ \A และ \z เพื่อตรงกับจุดเริ่มต้นและจุดสิ้นสุดของสตริง ^ และ $ ตรงกับจุดเริ่มต้น/สิ้นสุดของบรรทัด ด้วยเหตุผลที่ ^ และ $ ถูกใช้ผิดบ่อยครั้ง คุณต้องส่งตัวเลือก multiline: true ในกรณีที่คุณใช้สองตัวยึดเหล่านี้ใน regular expression ที่ให้มา ในกรณีส่วนใหญ่คุณควรใช้ \A และ \z

2.5 การรวมเข้า

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

class Coffee < ApplicationRecord
  validates :size, inclusion: { in: %w(small medium large),
    message: "%{value} ไม่ใช่ขนาดที่ถูกต้อง" }
end

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

ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวช่วยนี้คือ "ไม่ได้อยู่ในรายการ"

2.6 การยกเว้น

ข้อกลับของ การรวมเข้า คือ... การยกเว้น!

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

class Account < ApplicationRecord
  validates :subdomain, exclusion: { in: %w(www us ca jp),
    message: "%{value} ถูกสงวนไว้" }
end

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

ข้อความข้อผิดพลาดเริ่มต้นคือ "ถูกสงวน"

ในกรณีที่ไม่ใช่ enumerable แบบดั้งเดิม (เช่น Array) คุณสามารถให้ proc, lambda หรือสัญลักษณ์ที่คืนค่า enumerable ได้ หาก enumerable เป็นช่วงตัวเลข เวลา หรือวันที่แล้วทดสอบจะดำเนินการด้วย Range#cover? มิฉะนั้นด้วย include? เมื่อใช้ proc หรือ lambda ตัวอย่างนี้ผ่านตัวอย่างการตรวจสอบที่ต้องการ ตัวเลือกการจำกัดความยาวที่เป็นไปได้คือ:

  • :minimum - แอตทริบิวต์ต้องมีความยาวไม่น้อยกว่าค่าที่ระบุ
  • :maximum - แอตทริบิวต์ต้องมีความยาวไม่เกินค่าที่ระบุ
  • :in (หรือ :within) - ความยาวของแอตทริบิวต์ต้องอยู่ในช่วงที่กำหนด ค่าสำหรับตัวเลือกนี้ต้องเป็นช่วง
  • :is - ความยาวของแอตทริบิวต์ต้องเท่ากับค่าที่ระบุ

ข้อความข้อผิดพลาดเริ่มต้นขึ้นอยู่กับประเภทของการตรวจสอบความยาวที่กำลังดำเนินการ คุณสามารถกำหนดข้อความเหล่านี้เองโดยใช้ตัวเลือก :wrong_length, :too_long, และ :too_short และ %{count} เป็นตัวยึดตำแหน่งสำหรับจำนวนที่สอดคล้องกับการจำกัดความยาวที่ใช้งาน คุณยังสามารถใช้ตัวเลือก :message เพื่อระบุข้อความข้อผิดพลาด

class Person < ApplicationRecord
  validates :bio, length: { maximum: 1000,
    too_long: "%{count} ตัวอักษรเป็นค่าสูงสุดที่อนุญาต" }
end

โปรดทราบว่าข้อความข้อผิดพลาดเริ่มต้นเป็นพหูพจน์ (เช่น "สั้นเกินไป (ค่าต่ำสุดคือ %{count} ตัวอักษร)") ดังนั้นเมื่อ :minimum เป็น 1 คุณควรจัดหาข้อความข้อผิดพลาดที่กำหนดเองหรือใช้ presence: true แทน และเมื่อ :in หรือ :within มีขีดจำกัดต่ำสุดเป็น 1 คุณควรจัดหาข้อความข้อผิดพลาดที่กำหนดเองหรือเรียกใช้ presence ก่อน length

หมายเหตุ: สามารถใช้ตัวเลือกข้อจำกัดได้เพียงตัวเลือกเดียวนอกเหนือจากตัวเลือก :minimum และ :maximum ที่สามารถรวมกันได้

2.7 numericality

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

ในการระบุว่าอนุญาตเฉพาะตัวเลขจำนวนเต็มเท่านั้น ให้ตั้งค่า :only_integer เป็น true จากนั้นจะใช้ regular expression ต่อไปนี้ในการตรวจสอบค่าของแอตทริบิวต์

/\A[+-]?\d+\z/

มิฉะนั้น จะพยายามแปลงค่าเป็นตัวเลขโดยใช้ Float และ Float จะถูกแปลงเป็น BigDecimal โดยใช้ค่าความแม่นยำของคอลัมน์หรือสูงสุด 15 หลัก

class Player < ApplicationRecord
  validates :points, numericality: true
  validates :games_played, numericality: { only_integer: true }
end

ข้อความข้อผิดพลาดเริ่มต้นสำหรับ :only_integer คือ "ต้องเป็นจำนวนเต็ม"

นอกเหนือจาก :only_integer ช่วยในการตรวจสอบค่าที่เป็นตัวเลขเท่านั้น ช่วยให้รับค่าที่เป็นตัวอย่างของ Numeric และพยายามแปลงค่าถ้าเป็น String

หมายเหตุ: โดยค่าเริ่มต้น numericality ไม่อนุญาตค่า nil คุณสามารถใช้ตัวเลือก allow_nil: true เพื่ออนุญาตให้มี โปรดทราบว่าสำหรับคอลัมน์ Integer และ Float สตริงที่ว่างเปล่าจะถูกแปลงเป็น nil

ข้อความข้อผิดพลาดเริ่มต้นเมื่อไม่ระบุตัวเลือกคือ "ไม่ใช่ตัวเลข"

ยังมีตัวเลือกอื่น ๆ ที่สามารถใช้เพื่อเพิ่มข้อจำกัดในค่าที่ยอมรับได้:

  • :greater_than - ระบุว่าค่าต้องมากกว่าค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องมากกว่า %{count}"
  • :greater_than_or_equal_to - ระบุว่าค่าต้องมากกว่าหรือเท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องมากกว่าหรือเท่ากับ %{count}"
  • :equal_to - ระบุว่าค่าต้องเท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องเท่ากับ %{count}"
  • :less_than - ระบุว่าค่าต้องน้อยกว่าค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องน้อยกว่า %{count}"
  • :less_than_or_equal_to - ระบุว่าค่าต้องน้อยกว่าหรือเท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องน้อยกว่าหรือเท่ากับ %{count}"
  • :other_than - ระบุว่าค่าต้องไม่เท่ากับค่าที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องไม่เท่ากับ %{count}"
  • :in - ระบุว่าค่าต้องอยู่ในช่วงที่ระบุ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องอยู่ใน %{count}"
  • :odd - ระบุว่าค่าต้องเป็นจำนวนคี่ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องเป็นจำนวนคี่"
  • :even - ระบุว่าค่าต้องเป็นจำนวนคู่ ข้อความข้อผิดพลาดเริ่มต้นสำหรับตัวเลือกนี้คือ "ต้องเป็นจำนวนคู่" ### presence

ฟังก์ชันนี้ใช้ในการตรวจสอบว่าแอตทริบิวต์ที่ระบุไม่เป็นค่าว่าง โดยใช้เมธอด Object#blank? เพื่อตรวจสอบว่าค่าเป็น nil หรือสตริงที่ว่างเปล่า กล่าวคือสตริงที่ว่างเปล่าหรือประกอบด้วยช่องว่าง

class Person < ApplicationRecord
  validates :name, :login, :email, presence: true
end

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

class Supplier < ApplicationRecord
  has_one :account
  validates :account, presence: true
end

เพื่อที่จะตรวจสอบระเบียนที่เชื่อมโยงกันที่จำเป็นต้องมีการตรวจสอบ คุณต้องระบุตัวเลือก :inverse_of สำหรับการเชื่อมโยง:

class Order < ApplicationRecord
  has_many :line_items, inverse_of: :order
end

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

หากคุณตรวจสอบความเป็นมาตรฐานของวัตถุที่เชื่อมโยงผ่านความสัมพันธ์ has_one หรือ has_many มันจะตรวจสอบว่าวัตถุไม่ได้เป็น blank? หรือ marked_for_destruction?

เนื่องจาก false.blank? เป็นจริง หากคุณต้องการตรวจสอบความเป็นมาตรฐานของฟิลด์บูลีน คุณควรใช้การตรวจสอบดังต่อไปนี้:

# ค่า _ต้อง_ เป็น true หรือ false
validates :boolean_field_name, inclusion: [true, false]
# ค่า _ต้องไม่_ เป็น nil, กล่าวคือ true หรือ false
validates :boolean_field_name, exclusion: [nil]

โดยใช้การตรวจสอบหนึ่งในเหล่านี้ คุณจะรับประกันว่าค่าจะไม่เป็น nil ซึ่งจะทำให้ได้ค่า NULL ในกรณีส่วนใหญ่

ข้อความข้อผิดพลาดเริ่มต้นคือ "can’t be blank"

2.8 absence

ฟังก์ชันนี้ใช้ในการตรวจสอบว่าแอตทริบิวต์ที่ระบุไม่มีอยู่ โดยใช้เมธอด Object#present? เพื่อตรวจสอบว่าค่าไม่ใช่ nil หรือสตริงที่ว่างเปล่า กล่าวคือสตริงที่ว่างเปล่าหรือประกอบด้วยช่องว่าง

class Person < ApplicationRecord
  validates :name, :login, :email, absence: true
end

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

class LineItem < ApplicationRecord
  belongs_to :order
  validates :order, absence: true
end

เพื่อที่จะตรวจสอบระเบียนที่เชื่อมโยงกันที่ไม่มีอยู่ คุณต้องระบุตัวเลือก :inverse_of สำหรับการเชื่อมโยง:

class Order < ApplicationRecord
  has_many :line_items, inverse_of: :order
end

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

หากคุณตรวจสอบความเป็นมาตรฐานของวัตถุที่เชื่อมโยงผ่านความสัมพันธ์ has_one หรือ has_many มันจะตรวจสอบว่าวัตถุไม่ได้เป็น present? หรือ marked_for_destruction?

เนื่องจาก false.present? เป็นเท็จ หากคุณต้องการตรวจสอบความไม่มีอยู่ของฟิลด์บูลีน คุณควรใช้ validates :field_name, exclusion: { in: [true, false] }

ข้อความข้อผิดพลาดเริ่มต้นคือ "must be blank"

2.9 uniqueness

ผู้ช่วยนี้ตรวจสอบค่าของ attribute ว่าเป็นค่าที่ไม่ซ้ำกันก่อนที่วัตถุจะถูกบันทึกลงในฐานข้อมูล

class Account < ApplicationRecord
  validates :email, uniqueness: true
end

การตรวจสอบนี้จะเกิดขึ้นโดยการดำเนินการคิวรี SQL เข้าไปยังตารางของโมเดล โดยค้นหาบันทึกที่มีค่าเดียวกันใน attribute นั้น

มีตัวเลือก :scope ที่คุณสามารถใช้เพื่อระบุหนึ่งหรือหลาย attribute ที่ใช้ในการจำกัดการตรวจสอบความไม่ซ้ำกัน:

class Holiday < ApplicationRecord
  validates :name, uniqueness: { scope: :year,
    message: "should happen once per year" }
end

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

เพื่อเพิ่มข้อจำกัดความไม่ซ้ำกันในฐานข้อมูลของคุณ ใช้คำสั่ง add_index ในการเรียกใช้งานและรวมตัวเลือก unique: true

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

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

class Person < ApplicationRecord
  validates :name, uniqueness: { case_sensitive: false }
end

คำเตือน. โปรดทราบว่าบางฐานข้อมูลถูกกำหนดค่าให้ดำเนินการค้นหาโดยไม่สนใจตัวพิมพ์ใหญ่-เล็กอยู่แล้ว

มีตัวเลือก :conditions ที่คุณสามารถระบุเงื่อนไขเพิ่มเติมเป็นเฟรกเมนต์ SQL WHERE เพื่อจำกัดการค้นหาข้อจำกัดความไม่ซ้ำกัน (เช่น conditions: -> { where(status: 'active') })

ข้อความผิดพลาดเริ่มต้นคือ "has already been taken".

ดู validates_uniqueness_of เพื่อข้อมูลเพิ่มเติม

2.10 validates_associated

คุณควรใช้ผู้ช่วยนี้เมื่อโมเดลของคุณมีความสัมพันธ์ที่ต้องการตรวจสอบเสมอ ทุกครั้งที่คุณพยายามบันทึกวัตถุของคุณ valid? จะถูกเรียกใช้งานบนวัตถุที่เกี่ยวข้องแต่ละตัว

class Library < ApplicationRecord
  has_many :books
  validates_associated :books
end

การตรวจสอบนี้จะทำงานกับทุกประเภทของความสัมพันธ์

คำเตือน: อย่าใช้ validates_associated ทั้งสองด้านของความสัมพันธ์ของคุณ มันจะเรียกใช้งานกันเองในลูปไม่สิ้นสุด

ข้อความผิดพลาดเริ่มต้นสำหรับ validates_associated คือ "is invalid". โปรดทราบว่าแต่ละวัตถุที่เกี่ยวข้องจะมีคอลเลกชันของข้อผิดพลาดของตัวเอง ข้อผิดพลาดไม่สามารถส่งผ่านไปยังโมเดลที่เรียกใช้งานได้

หมายเหตุ: validates_associated สามารถใช้ได้เฉพาะกับวัตถุ ActiveRecord เท่านั้น สิ่งที่เรียกใช้ก่อนหน้านี้สามารถใช้กับวัตถุใดก็ได้ที่รวม ActiveModel::Validations

2.11 validates_each

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

class Person < ApplicationRecord
  validates_each :name, :surname do |record, attr, value|
    record.errors.add(attr, 'must start with upper case') if /\A[[:lower:]]/.match?(value)
  end
end

บล็อกจะรับ record, ชื่อของ attribute และค่าของ attribute

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

2.12 validates_with

ช่วยให้คลาสเฉพาะสำหรับการตรวจสอบส่ง record ไปยังคลาสที่แยกออกมาเพื่อทำการตรวจสอบ

class GoodnessValidator < ActiveModel::Validator
  def validate(record)
    if record.first_name == "Evil"
      record.errors.add :base, "This person is evil"
    end
  end
end

class Person < ApplicationRecord
  validates_with GoodnessValidator
end

ไม่มีข้อความผิดพลาดเริ่มต้นสำหรับ validates_with คุณต้องเพิ่มข้อผิดพลาดเองในคลาสตรวจสอบ

หมายเหตุ: ข้อผิดพลาดที่เพิ่มใน record.errors[:base] เกี่ยวข้องกับสถานะของ record โดยรวม

ในการดำเนินการ validate method คุณต้องยอมรับพารามิเตอร์ record ในการกำหนดเมธอด ซึ่งเป็น record ที่จะถูกตรวจสอบ

หากคุณต้องการเพิ่มข้อผิดพลาดใน attribute ที่ระบุ ให้ส่งมันเป็นอาร์กิวเมนต์แรก เช่น record.errors.add(:first_name, "please choose another name") เราจะพูดถึง [validation errors][] ในรายละเอียดเพิ่มเติมในภายหลัง

def validate(record)
  if record.some_field != "acceptable"
    record.errors.add :some_field, "this field is unacceptable"
  end
end

ช่วยเหลือ validates_with รับคลาสหรือรายการคลาสที่จะใช้สำหรับการตรวจสอบ

class Person < ApplicationRecord
  validates_with MyValidator, MyOtherValidator, on: :create
end

เช่นเดียวกับการตรวจสอบอื่น ๆ validates_with รับ :if, :unless และ :on options หากคุณส่งตัวเลือกอื่น ๆ มันจะส่งตัวเลือกเหล่านั้นไปยังคลาสตรวจสอบเป็น options:

class GoodnessValidator < ActiveModel::Validator
  def validate(record)
    if options[:fields].any? { |field| record.send(field) == "Evil" }
      record.errors.add :base, "This person is evil"
    end
  end
end

class Person < ApplicationRecord
  validates_with GoodnessValidator, fields: [:first_name, :last_name]
end

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

หาก validator ของคุณซับซ้อนพอที่คุณต้องการตัวแปรอินสแตนซ์คุณสามารถใช้วัตถุรูบีธร้อยแทนได้ง่าย:

class Person < ApplicationRecord
  validate do |person|
    GoodnessValidator.new(person).validate
  end
end

class GoodnessValidator
  def initialize(person)
    @person = person
  end

  def validate
    if some_complex_condition_involving_ivars_and_private_methods?
      @person.errors.add :base, "This person is evil"
    end
  end

  # ...
end

เราจะพูดถึง custom validations ในภายหลัง

validation errors

3 Common Validation Options

มีตัวเลือกที่ใช้กันอย่างแพร่หลายที่รองรับโดย validators ที่เราได้กล่าวถึงเพิ่มเติม มาเริ่มต้นกันเลย!

หมายเหตุ: ไม่ใช่ทุกตัวเลือกเหล่านี้รองรับโดย validators ทุกตัว โปรดอ้างอิงเอกสาร API สำหรับ ActiveModel::Validations

โดยใช้เมธอดการตรวจสอบใด ๆ ที่เรากล่าวถึงเพิ่มเติม ยังมีรายการตัวเลือกที่ใช้ร่วมกับ validators ร่วมกัน เราจะพูดถึงเรื่องเหล่านี้ตอนนี้!

  • :allow_nil: ข้ามการตรวจสอบหาก attribute เป็น nil
  • :allow_blank: ข้ามการตรวจสอบหาก attribute เป็น blank
  • :message: ระบุข้อความผิดพลาดที่กำหนดเอง
  • :on: ระบุบริบทที่การตรวจสอบนี้มีผล
  • :strict: เรียกข้อยกเว้นเมื่อการตรวจสอบล้มเหลว
  • :if และ :unless: ระบุเมื่อควรหรือไม่ควรมีการตรวจสอบ ### :allow_nil

ตัวเลือก :allow_nil จะข้ามการตรวจสอบเมื่อค่าที่กำลังตรวจสอบเป็น nil.

class Coffee < ApplicationRecord
  validates :size, inclusion: { in: %w(small medium large),
    message: "%{value} ไม่ใช่ขนาดที่ถูกต้อง" }, allow_nil: true
end
irb> Coffee.create(size: nil).valid?
=> true
irb> Coffee.create(size: "mega").valid?
=> false

สำหรับตัวเลือกเต็มรูปแบบของอาร์กิวเมนต์ข้อความโปรดดูที่ เอกสารข้อความ.

3.1 :allow_blank

ตัวเลือก :allow_blank คล้ายกับตัวเลือก :allow_nil ตัวเลือกนี้จะทำให้การตรวจสอบผ่านได้หากค่าของแอตทริบิวต์เป็น blank? เช่น nil หรือสตริงที่ว่างเปล่าเป็นต้น

class Topic < ApplicationRecord
  validates :title, length: { is: 5 }, allow_blank: true
end
irb> Topic.create(title: "").valid?
=> true
irb> Topic.create(title: nil).valid?
=> true

3.2 :message

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

ตัวเลือก :message รับค่าเป็น String หรือ Proc

ค่า String ของ :message สามารถมี %{value}, %{attribute}, และ %{model} ที่อาจมีหรือไม่มีได้ และจะถูกแทนที่โดยอัตโนมัติเมื่อการตรวจสอบล้มเหลว การแทนที่นี้จะถูกทำโดยใช้ i18n gem และตัวยึดต้องตรงกันอย่างเที่ยงตรง ไม่อนุญาตให้มีช่องว่าง

class Person < ApplicationRecord
  # ข้อความที่กำหนดแบบคงที่
  validates :name, presence: { message: "ต้องระบุ" }

  # ข้อความที่มีค่าแอตทริบิวต์แบบไดนามิก ค่า %{value} จะถูกแทนที่
  # ด้วยค่าจริงของแอตทริบิวต์ และ %{attribute} และ %{model}
  # ก็สามารถใช้ได้
  validates :age, numericality: { message: "%{value} ดูเหมือนผิด" }
end

ค่า Proc ของ :message รับอาร์กิวเมนต์สองตัว: ออบเจกต์ที่กำลังตรวจสอบ และแฮชที่มีคีย์-ค่าเป็น :model, :attribute, และ :value

class Person < ApplicationRecord
  validates :username,
    uniqueness: {
      # object = ออบเจกต์ person ที่กำลังตรวจสอบ
      # data = { model: "Person", attribute: "Username", value: <username> }
      message: ->(object, data) do
        "สวัสดี #{object.name}, #{data[:value]} ถูกใช้งานแล้ว."
      end
    }
end

3.3 :on

ตัวเลือก :on ช่วยให้คุณระบุเมื่อการตรวจสอบควรเกิดขึ้น พฤติกรรมเริ่มต้นสำหรับช่วยในการตรวจสอบที่มีอยู่ทั้งหมดคือการทำงานเมื่อบันทึก (ทั้งเมื่อคุณสร้างบันทึกใหม่และเมื่อคุณอัปเดต) หากคุณต้องการเปลี่ยนแปลงคุณสามารถใช้ on: :create เพื่อให้การตรวจสอบเกิดขึ้นเฉพาะเมื่อสร้างบันทึกใหม่หรือ on: :update เพื่อให้การตรวจสอบเกิดขึ้นเฉพาะเมื่ออัปเดตบันทึก

class Person < ApplicationRecord
  # จะสามารถอัปเดตอีเมลด้วยค่าที่ซ้ำกันได้
  validates :email, uniqueness: true, on: :create

  # จะสามารถสร้างบันทึกด้วยอายุที่ไม่ใช่ตัวเลขได้
  validates :age, numericality: true, on: :update

  # ค่าเริ่มต้น (ตรวจสอบทั้งการสร้างและการอัปเดต)
  validates :name, presence: true
end

คุณยังสามารถใช้ on: เพื่อกำหนดบริบทที่กำหนดเองได้ บริบทที่กำหนดเองจะต้องถูกเรียกใช้โดยชื่อของบริบทที่ผ่านมาให้กับ valid?, invalid?, หรือ save

class Person < ApplicationRecord
  validates :email, uniqueness: true, on: :account_setup
  validates :age, numericality: true, on: :account_setup
end
irb> person = Person.new(age: 'สามสิบสาม')
irb> person.valid?
=> true
irb> person.valid?(:account_setup)
=> false
irb> person.errors.messages
=> {:email=>["ถูกใช้ไปแล้ว"], :age=>["ไม่ใช่ตัวเลข"]}

person.valid?(:account_setup) ทำการตรวจสอบ validations ทั้งสองโดยไม่บันทึก model ลงฐานข้อมูล person.save(context: :account_setup) ทำการตรวจสอบ person ใน context account_setup ก่อนที่จะบันทึก

การส่งอาร์เรย์ของสัญลักษณ์เป็นสิ่งที่ยอมรับได้เช่นกัน

class Book
  include ActiveModel::Validations

  validates :title, presence: true, on: [:update, :ensure_title]
end
irb> book = Book.new(title: nil)
irb> book.valid?
=> true
irb> book.valid?(:ensure_title)
=> false
irb> book.errors.messages
=> {:title=>["ต้องไม่เป็นค่าว่าง"]}

เมื่อถูกเรียกใช้โดย context ที่ระบุโดยชัดเจน validations จะถูกเรียกใช้สำหรับ context นั้น ๆ รวมถึง validations ที่ไม่มี context

class Person < ApplicationRecord
  validates :email, uniqueness: true, on: :account_setup
  validates :age, numericality: true, on: :account_setup
  validates :name, presence: true
end
irb> person = Person.new
irb> person.valid?(:account_setup)
=> false
irb> person.errors.messages
=> {:email=>["ถูกใช้ไปแล้ว"], :age=>["ไม่ใช่ตัวเลข"], :name=>["ต้องไม่เป็นค่าว่าง"]}

เราจะพิจารณากรณีการใช้งานเพิ่มเติมสำหรับ on: ในคู่มือของ callbacks

4 Strict Validations

คุณยังสามารถระบุ validations เพื่อให้เป็นเครื่องหมายเข้มและเรียก ActiveModel::StrictValidationFailed เมื่อวัตถุไม่ถูกต้อง

class Person < ApplicationRecord
  validates :name, presence: { strict: true }
end
irb> Person.new.valid?
ActiveModel::StrictValidationFailed: ชื่อต้องไม่เป็นค่าว่าง

ยังมีความสามารถในการส่งข้อยกเว้นที่กำหนดเองไปยังตัวเลือก :strict ด้วย

class Person < ApplicationRecord
  validates :token, presence: true, uniqueness: true, strict: TokenGenerationException
end
irb> Person.new.valid?
TokenGenerationException: โทเค็นต้องไม่เป็นค่าว่าง

5 การตรวจสอบเงื่อนไข

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

5.1 การใช้สัญลักษณ์กับ :if และ :unless

คุณสามารถเชื่อมโยงตัวเลือก :if และ :unless กับสัญลักษณ์ที่สอดคล้องกับชื่อของเมธอดที่จะถูกเรียกใช้ก่อนการตรวจสอบ นี่เป็นตัวเลือกที่ใช้มากที่สุด

class Order < ApplicationRecord
  validates :card_number, presence: true, if: :paid_with_card?

  def paid_with_card?
    payment_type == "card"
  end
end

5.2 การใช้ Proc กับ :if และ :unless

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

class Account < ApplicationRecord
  validates :password, confirmation: true,
    unless: Proc.new { |a| a.password.blank? }
end

เนื่องจาก lambda เป็นชนิดของ Proc คุณยังสามารถใช้เงื่อนไขแบบอินไลน์โดยใช้ไวยากรณ์ที่สั้นลง

validates :password, confirmation: true, unless: -> { password.blank? }

6 การจัดกลุ่มการตรวจสอบเงื่อนไข

บางครั้งการมีการตรวจสอบหลาย ๆ รายการที่ใช้เงื่อนไขเดียวกันจะเป็นประโยชน์ คุณสามารถทำได้ง่ายๆ โดยใช้ with_options ruby class User < ApplicationRecord with_options if: :is_admin? do |admin| admin.validates :password, length: { minimum: 10 } admin.validates :email, presence: true end end

การตรวจสอบความถูกต้องทั้งหมดภายในบล็อก with_options จะผ่านเงื่อนไข if: :is_admin? โดยอัตโนมัติ

6.1 การรวมเงื่อนไขการตรวจสอบ

ในกรณีอื่น ๆ เมื่อมีเงื่อนไขหลายอย่างที่กำหนดว่าการตรวจสอบความถูกต้องควรเกิดขึ้นหรือไม่ สามารถใช้ Array ได้ นอกจากนี้คุณยังสามารถใช้ทั้ง :if และ :unless ในการตรวจสอบเดียวกันได้

class Computer < ApplicationRecord
  validates :mouse, presence: true,
                    if: [Proc.new { |c| c.market.retail? }, :desktop?],
                    unless: Proc.new { |c| c.trackpad.present? }
end

การตรวจสอบเกิดขึ้นเฉพาะเมื่อทุกเงื่อนไข :if และไม่มีเงื่อนไข :unless ที่ประเมินค่าเป็น true

7 การทำการตรวจสอบที่กำหนดเอง

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

7.1 ตัวตรวจสอบที่กำหนดเอง

ตัวตรวจสอบที่กำหนดเองเป็นคลาสที่สืบทอดมาจาก ActiveModel::Validator คลาสเหล่านี้ต้องประมวลผลเมธอด validate ซึ่งรับอาร์กิวเมนต์เป็นเร็คคอร์ดและดำเนินการตรวจสอบบนเร็คคอร์ด ตัวตรวจสอบที่กำหนดเองจะถูกเรียกใช้โดยใช้เมธอด validates_with

class MyValidator < ActiveModel::Validator
  def validate(record)
    unless record.name.start_with? 'X'
      record.errors.add :name, "กรุณาใส่ชื่อที่ขึ้นต้นด้วย X!"
    end
  end
end

class Person < ApplicationRecord
  validates_with MyValidator
end

วิธีที่ง่ายที่สุดในการเพิ่มตัวตรวจสอบที่กำหนดเองสำหรับการตรวจสอบแต่ละแอตทริบิวต์คือ ActiveModel::EachValidator ในกรณีนี้ คลาสตัวตรวจสอบที่กำหนดเองต้องประมวลผลเมธอด validate_each ซึ่งรับอาร์กิวเมนต์สามตัว: เร็คคอร์ด แอตทริบิวต์ที่จะตรวจสอบ และค่าของแอตทริบิวต์ในเรคคอร์ดที่ผ่านมา

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless URI::MailTo::EMAIL_REGEXP.match?(value)
      record.errors.add attribute, (options[:message] || "ไม่ใช่อีเมล")
    end
  end
end

class Person < ApplicationRecord
  validates :email, presence: true, email: true
end

ตามที่แสดงในตัวอย่าง คุณยังสามารถรวมการตรวจสอบมาตรฐานกับตัวตรวจสอบที่กำหนดเองของคุณได้เช่นกัน

7.2 เมธอดที่กำหนดเอง

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

คุณสามารถส่งสัญลักษณ์มากกว่าหนึ่งสัญลักษณ์สำหรับแต่ละเมธอดคลาส และการตรวจสอบที่เกี่ยวข้องจะถูกเรียกใช้ในลำดับเดียวกันกับที่ลงทะเบียน

เมื่อคุณเรียกใช้เมธอด valid? จะตรวจสอบว่าคอลเลกชัน errors ว่างเปล่า ดังนั้นเมธอดการตรวจสอบที่กำหนดเองของคุณควรเพิ่มข้อผิดพลาดในนั้นเมื่อคุณต้องการให้การตรวจสอบล้มเหลว:

class Invoice < ApplicationRecord
  validate :expiration_date_cannot_be_in_the_past,
    :discount_cannot_be_greater_than_total_value

  def expiration_date_cannot_be_in_the_past
    if expiration_date.present? && expiration_date < Date.today
      errors.add(:expiration_date, "ไม่สามารถเป็นวันที่ผ่านมาได้")
    end
  end

  def discount_cannot_be_greater_than_total_value
    if discount > total_value
      errors.add(:discount, "ไม่สามารถมีส่วนลดมากกว่ามูลค่ารวมได้")
    end
  end
end

ตามค่าเริ่มต้น การตรวจสอบเช่นนี้จะทำงานทุกครั้งที่คุณเรียกใช้ valid? หรือบันทึกวัตถุ แต่คุณยังสามารถควบคุมเมื่อจะเรียกใช้การตรวจสอบที่กำหนดเองเหล่านี้ได้โดยให้ตัวเลือก :on ให้กับเมธอด validate ด้วย :create หรือ :update ```ruby class Invoice < ApplicationRecord validate :active_customer, on: :create

def active_customer errors.add(:customer_id, "ไม่ได้เปิดใช้งาน") unless customer.active? end end ```

ดูส่วนด้านบนสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ :on

7.3 การระบุ Validators

หากคุณต้องการหา Validators ทั้งหมดสำหรับอ็อบเจ็กต์ที่กำหนดให้ คุณสามารถใช้ validators ได้

ตัวอย่างเช่น หากเรามีโมเดลต่อไปนี้ที่ใช้ Validator ที่กำหนดเองและ Validator ที่มีอยู่แล้ว:

class Person < ApplicationRecord
  validates :name, presence: true, on: :create
  validates :email, format: URI::MailTo::EMAIL_REGEXP
  validates_with MyOtherValidator, strict: true
end

เราสามารถใช้ validators บนโมเดล "Person" เพื่อแสดงรายการ Validators ทั้งหมด หรือตรวจสอบฟิลด์ที่ระบุโดยใช้ validators_on ได้

irb> Person.validators
#=> [#<ActiveRecord::Validations::PresenceValidator:0x10b2f2158
      @attributes=[:name], @options={:on=>:create}>,
     #<MyOtherValidatorValidator:0x10b2f17d0
      @attributes=[:name], @options={:strict=>true}>,
     #<ActiveModel::Validations::FormatValidator:0x10b2f0f10
      @attributes=[:email],
      @options={:with=>URI::MailTo::EMAIL_REGEXP}>]
     #<MyOtherValidator:0x10b2f0948 @options={:strict=>true}>]

irb> Person.validators_on(:name)
#=> [#<ActiveModel::Validations::PresenceValidator:0x10b2f2158
      @attributes=[:name], @options={on: :create}>]

8 การทำงานกับ Validation Errors

เมื่อใช้ valid? และ invalid? เราจะได้รับสถานะสรุปเกี่ยวกับความถูกต้อง อย่างไรก็ตามคุณสามารถตรวจสอบข้อผิดพลาดแต่ละข้อได้โดยใช้เมธอดต่างๆ จากคอลเลกชัน errors

ต่อไปนี้คือรายการเมธอดที่ใช้บ่อยที่สุด โปรดอ้างอิงที่เอกสาร ActiveModel::Errors เพื่อดูรายการเมธอดทั้งหมดที่มีอยู่

8.1 errors

เป็นทางเข้าที่คุณสามารถเข้าถึงรายละเอียดต่างๆ ของแต่ละข้อผิดพลาด

เมื่อเรียกใช้งานจะได้รับอินสแตนซ์ของคลาส ActiveModel::Errors ที่มีข้อผิดพลาดทั้งหมด แต่ละข้อผิดพลาดจะถูกแทนที่ด้วยอ็อบเจ็กต์ ActiveModel::Error

class Person < ApplicationRecord
  validates :name, presence: true, length: { minimum: 3 }
end
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.full_messages
=> ["Name can’t be blank", "Name is too short (minimum is 3 characters)"]

irb> person = Person.new(name: "John Doe")
irb> person.valid?
=> true
irb> person.errors.full_messages
=> []

irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.first.details
=> {:error=>:too_short, :count=>3}

8.2 errors[]

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

class Person < ApplicationRecord
  validates :name, presence: true, length: { minimum: 3 }
end
irb> person = Person.new(name: "John Doe")
irb> person.valid?
=> true
irb> person.errors[:name]
=> []

irb> person = Person.new(name: "JD")
irb> person.valid?
=> false
irb> person.errors[:name]
=> ["is too short (minimum is 3 characters)"]

irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors[:name]
=> ["can’t be blank", "is too short (minimum is 3 characters)"]

8.3 errors.where และ Error Object

บางครั้งเราอาจต้องการข้อมูลเพิ่มเติมเกี่ยวกับแต่ละข้อผิดพลาดนอกเหนือจากข้อความข้อผิดพลาด แต่ละข้อผิดพลาดจะถูกแคปซูลเป็นอ็อบเจ็กต์ ActiveModel::Error และเมธอด where เป็นวิธีที่ใช้บ่อยที่สุดในการเข้าถึง

where จะคืนอาร์เรย์ของอ็อบเจ็กต์ข้อผิดพลาดที่ผ่านการกรองตามเงื่อนไขต่างๆ

class Person < ApplicationRecord
  validates :name, presence: true, length: { minimum: 3 }
end

เราสามารถกรองเฉพาะ attribute เท่านั้นโดยส่งมันเป็นพารามิเตอร์แรกไปที่ errors.where(:attr) พารามิเตอร์ที่สองใช้สำหรับกรอง type ของข้อผิดพลาดที่เราต้องการโดยเรียกใช้ errors.where(:attr, :type) ```irb irb> person = Person.new irb> person.valid? => false

irb> person.errors.where(:name) => [ ... ] # ข้อผิดพลาดทั้งหมดสำหรับ attribute :name

irb> person.errors.where(:name, :too_short) => [ ... ] # ข้อผิดพลาด :too_short สำหรับ attribute :name ```

สุดท้ายเราสามารถกรองโดยใช้ options ที่อาจมีอยู่ในวัตถุข้อผิดพลาดประเภทที่กำหนดไว้

irb> person = Person.new
irb> person.valid?
=> false

irb> person.errors.where(:name, :too_short, minimum: 3)
=> [ ... ] # ข้อผิดพลาดทั้งหมดของชื่อที่สั้นเกินไปและค่าต่ำสุดคือ 2

คุณสามารถอ่านข้อมูลต่าง ๆ จากวัตถุข้อผิดพลาดเหล่านี้ได้:

irb> error = person.errors.where(:name).last

irb> error.attribute
=> :name
irb> error.type
=> :too_short
irb> error.options[:count]
=> 3

คุณยังสามารถสร้างข้อผิดพลาดได้:

irb> error.message
=> "is too short (minimum is 3 characters)"
irb> error.full_message
=> "Name is too short (minimum is 3 characters)"

เมธอด full_message สร้างข้อความที่ใช้งานง่ายมากขึ้น โดยเติมชื่อแอตทริบิวต์ที่เป็นตัวพิมพ์ใหญ่ไว้ด้านหน้า (หากต้องการกำหนดรูปแบบที่ full_message ใช้ โปรดดูที่ คู่มือ I18n.)

8.4 errors.add

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

class Person < ApplicationRecord
  validate do |person|
    errors.add :name, :too_plain, message: "is not cool enough"
  end
end
irb> person = Person.create
irb> person.errors.where(:name).first.type
=> :too_plain
irb> person.errors.where(:name).first.full_message
=> "Name is not cool enough"

8.5 errors[:base]

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

class Person < ApplicationRecord
  validate do |person|
    errors.add :base, :invalid, message: "This person is invalid because ..."
  end
end
irb> person = Person.create
irb> person.errors.where(:base).first.full_message
=> "This person is invalid because ..."

8.6 errors.size

เมธอด size คืนค่าจำนวนข้อผิดพลาดทั้งหมดสำหรับวัตถุ

class Person < ApplicationRecord
  validates :name, presence: true, length: { minimum: 3 }
end
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.size
=> 2

irb> person = Person.new(name: "Andrea", email: "[email protected]")
irb> person.valid?
=> true
irb> person.errors.size
=> 0

8.7 errors.clear

เมธอด clear ใช้เมื่อคุณต้องการล้างคอลเลกชัน errors อย่างตั้งใจ แน่นอนว่าการเรียกใช้ errors.clear กับวัตถุที่ไม่ถูกต้องจะไม่ทำให้มันถูกต้อง: คอลเลกชัน errors จะว่างเปล่าตอนนี้ แต่ครั้งต่อไปที่คุณเรียกใช้ valid? หรือเมธอดใด ๆ ที่พยายามบันทึกวัตถุนี้ลงในฐานข้อมูล การตรวจสอบจะเริ่มทำงานอีกครั้ง หากการตรวจสอบใด ๆ ล้มเหลว คอลเลกชัน errors จะเต็มอีกครั้ง

class Person < ApplicationRecord
  validates :name, presence: true, length: { minimum: 3 }
end
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.empty?
=> false

irb> person.errors.clear
irb> person.errors.empty?
=> true

irb> person.save
=> false

irb> person.errors.empty?
=> false

9 แสดงข้อผิดพลาดการตรวจสอบในมุมมอง

เมื่อคุณสร้างโมเดลและเพิ่มการตรวจสอบหากโมเดลนั้นถูกสร้างผ่านแบบฟอร์มเว็บ คุณอาจต้องการแสดงข้อความข้อผิดพลาดเมื่อการตรวจสอบหนึ่งในนั้นล้มเหลว เนื่องจากแอปพลิเคชันแต่ละตัวจัดการเรื่องนี้ได้ต่างกัน ดังนั้น Rails ไม่รวมเครื่องมือช่วยในการสร้างข้อความเหล่านี้โดยตรง อย่างไรก็ตาม เนื่องจากมีจำนวนมากของเมธอดที่ Rails ให้คุณใช้สื่อสารกับการตรวจสอบความถูกต้องทั่วไป คุณสามารถสร้างของคุณเองได้ นอกจากนี้ เมื่อสร้าง scaffold Rails จะใส่ ERB เข้าไปใน _form.html.erb ที่เกิดขึ้นที่แสดงรายการข้อผิดพลาดทั้งหมดบนโมเดลนั้น

ถ้าเรามีโมเดลที่ถูกบันทึกในตัวแปรอินสแตนซ์ที่ชื่อ @article มันจะมีลักษณะดังนี้:

<% if @article.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@article.errors.count, "error") %> ไม่อนุญาตให้บันทึกบทความนี้:</h2>

    <ul>
      <% @article.errors.each do |error| %>
        <li><%= error.full_message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

นอกจากนี้ หากคุณใช้ช่วยในการสร้างฟอร์มของ Rails เมื่อเกิดข้อผิดพลาดในการตรวจสอบความถูกต้องบนฟิลด์ มันจะสร้าง <div> เพิ่มเติมรอบการป้อนข้อมูล

<div class="field_with_errors">
  <input id="article_title" name="article[title]" size="30" type="text" value="">
</div>

คุณสามารถกำหนดสไตล์ของ div นี้ได้ตามต้องการ ตัวอย่างของ scaffold เริ่มต้นที่ Rails สร้าง เช่น เพิ่มกฎ CSS ดังนี้:

.field_with_errors {
  padding: 2px;
  background-color: red;
  display: table;
}

นี้หมายความว่าฟิลด์ใดก็ตามที่มีข้อผิดพลาดจะมีเส้นขอบสีแดงขนาด 2 พิกเซล

ข้อเสนอแนะ

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

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

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

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

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