Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีที่เบาในการจัดการสถานการณ์การตรวจสอบที่แตกต่างกัน

(ฉันส่งโพสต์นี้ไปที่รายการของฉันเมื่อสองสามเดือนก่อน ถ้าคุณชอบและต้องการอ่านเพิ่มเติม คุณควรสมัคร!)

วันก่อนฉันเจอสถานการณ์แปลกๆ กับแอปของฉัน

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

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

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

if และ unless ?

การตรวจสอบรองรับ :if และ :unless พารามิเตอร์ แต่สิ่งนี้ไม่สะอาดเสมอไป:

app/models/article.rb
class Article < ActiveRecord::Base
  # validate in draft mode
  validates_presence_of :author_id 

  # validate only when published
  validates_presence_of :body, unless: lambda { |o| o.draft? }
  
  ...
end

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

ฟีเจอร์ Rails ที่ไม่ค่อยมีใครรู้จักและมีเอกสารประกอบ

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

เอกสารประกอบสำหรับบริบทที่กำหนดเองค่อนข้างบาง สิ่งเดียวที่ฉันพบในเอกสาร API คือที่นี่ และเอกสาร API สำหรับการตรวจสอบเหล่านี้ไม่ได้กล่าวถึงบริบทที่กำหนดเองเลย! สิ่งนี้ทำให้ยากเป็นพิเศษ – หากคุณไม่รู้ว่าสิ่งที่เรียกว่าอะไร คุณจะค้นหาเอกสารเพิ่มเติมได้อย่างไร

ในที่สุดฉันก็พบภาพรวมที่ดีที่นี่:https://blog.arkency.com/2014/04/mastering-rails-validations-contexts/ มันคุ้มค่าที่จะอ่าน ลองดูตัวอย่างของเรา:

app/models/article.rb
class Article < ActiveRecord::Base
  # validate in draft mode
  validates_presence_of :author_id
 
  # validate only when published
  validates_presence_of :body, on: :publish
  ...
end
app/controllers/article_controller.rb
class ArticleController < ApplicationController
  respond_to :html

  def create
    @article = Article.create(article_params)
    respond_with @article
  end

  def publish
    @article = Article.find(params[:id])
    @article.attributes = article_params
    @article.save(context: :publish)
    respond_with @article
  end

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

ก็ไม่เลวนะ! ที่แปลกอย่างเดียวคือต้องใช้ save แทน update ในวิธีการเผยแพร่ ที่เกิดขึ้นเพราะ update ไม่สามารถใช้บริบทการตรวจสอบเป็นพารามิเตอร์ได้ (อาจเป็นโอกาสสำหรับคำขอดึง)

อยู่เหนือการประหยัด

บริบทการตรวจสอบความถูกต้องแบบกำหนดเองมีประโยชน์มากกว่าการบันทึกเรกคอร์ดด้วยวิธีต่างๆ บริบทใช้งานได้ valid? :

@article.valid?(:publish)

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

DHH สร้างเมธอดที่ลงท้ายด้วย -able? ที่มอบหมายให้ valid?(:context) ). ฉันชอบรูปลักษณ์ของมันมาก:

app/models/article.rb
class Article
  validate :has_been_published, on: :view
  validate :is_not_spam, on: :view

  def viewable?
    valid? :view
  end

  private

  def has_been_published
    if published_at.future?
      errors.add(:published_at, "is in the future")
    end
  end

  def is_not_spam
    if is_spam?(body)
      errors.add(:body, "has been detected as spam")
    end
  end
end

วิธีนี้ เมื่อคุณตรวจสอบ คุณจะได้ข้อมูลมากกว่าแค่ true หรือ false :

unless @article.viewable?
  # @article.errors is now filled out
end

บทความสามารถดูได้หรือไม่? แล้วทำไมไม่ล่ะ

แค่เบาก็พอ

มีอีกสองสามวิธีที่คุณสามารถรับพฤติกรรมการตรวจสอบประเภทนี้ได้ คุณสามารถสร้าง ActiveModel . ที่กำหนดเองได้ วัตถุบริการที่มีการตรวจสอบความถูกต้องของตนเอง คุณสามารถใช้ :if หรือ :unless ในการตรวจสอบของคุณ แต่เช่นเดียวกับหลายๆ อย่างใน Rails บริบทการตรวจสอบที่กำหนดเองเป็นการประนีประนอมที่ดีระหว่างความสามารถในการอ่านและความยืดหยุ่น