จะกำหนดประเภทข้อผิดพลาดที่กำหนดเองใน Ruby และ / หรือ Rails ได้ที่ไหน


149

มีวิธีปฏิบัติที่ดีที่สุดสำหรับการกำหนดประเภทข้อผิดพลาดที่กำหนดเองในแอปพลิเคชัน Ruby library (gem) หรือ Ruby on Rails หรือไม่? โดยเฉพาะ:

  1. พวกเขาอยู่ในโครงสร้างในโครงการที่ไหน? ไฟล์แยกต่างหากซึ่งสอดคล้องกับโมดูล / คำจำกัดความของคลาสที่เกี่ยวข้อง
  2. จะมีการประชุมใด ๆ ที่สร้างเมื่อไปและเมื่อไม่ได้ที่จะสร้างข้อผิดพลาดชนิดใหม่หรือไม่?

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

โอ้และเพียงเพราะฉันรู้สึกว่าการเรียก "ประเภทข้อผิดพลาด" เหล่านี้เป็นสิ่งที่คลุมเครือสิ่งที่ฉันหมายถึงคือ:

class AuthenticationError < StandardError; end
class InvalidUsername < AuthenticationError; end

คำตอบ:


219

สำหรับอัญมณี

ฉันเคยเห็นหลายครั้งที่คุณกำหนดข้อยกเว้นด้วยวิธีนี้:

gem_dir / lib / gem_name / exceptions.rb

และกำหนดเป็น:

module GemName

  class AuthenticationError < StandardError; end
  class InvalidUsername < AuthenticationError; end

end

ตัวอย่างนี้จะเป็นอะไรแบบนี้ในhttparty

สำหรับ Ruby on Rails

วางไว้ใน lib / โฟลเดอร์ของคุณภายใต้ไฟล์ที่ชื่อว่า exceptions.rb ซึ่งจะมีลักษณะดังนี้:

module Exceptions
  class AuthenticationError < StandardError; end
  class InvalidUsername < AuthenticationError; end
end

และคุณจะใช้มันในลักษณะนี้:

raise Exceptions::InvalidUsername

สำหรับอัญมณีดูเหมือนว่าคุณอาจต้องรวมไฟล์ข้อยกเว้นด้วย ดูตัวอย่างนี้อีกครั้งจากhttparty: github.com/jnunemaker/httparty/blob/...
เจสัน Swett

37
ทำไมต้องเนมสเปซลงในExceptionsโมดูล
ABMagil

13
ฉันคิดว่านั่น/libอาจไม่ใช่ที่สำหรับความผิดพลาด เป็นแอปพลิเคชันที่เฉพาะเจาะจงมากและฉันรู้สึกว่ารหัสที่ฉันใส่/libนั้นมีความหมายว่าเป็นรหัสที่สามารถนำมาใช้ซ้ำในแอปพลิเคชันอื่น
wuliwong

1
คำแนะนำ Ruby on Rails ไม่ได้ผลสำหรับฉัน - จำเป็นต้องมีขั้นตอนเพิ่มเติมบางอย่างในการโหลดไฟล์ใหม่นี้ในกรณีทั่วไปหรือไม่?
Meekohi

1
@ABMagil ดูเหมือนว่าฉันจะต้องเป็นอย่างUnable to autoload constant Exceptions, expected /app/lib/exceptions.rb to define itอื่นตัวเลือกอื่นจะเป็นหนึ่งชั้นเรียนต่อข้อยกเว้นที่ฉันคิดว่า
ryan2johnson9

25

ฉันคิดว่าเพื่อให้มีไฟล์แหล่งที่มาที่เหนียวแน่นในโครงการของคุณคุณควรกำหนดข้อผิดพลาดในคลาสที่อาจทำให้เกิดข้อผิดพลาดและไม่มีที่อื่น

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


8
ในทางทฤษฎีแล้วคุณจะถูกต้องเกิดอะไรขึ้นเมื่อข้อผิดพลาดเดียวกันสามารถยกขึ้นในชั้นเรียนต่าง ๆ ในสถานการณ์ที่แตกต่างกันโดยสิ้นเชิง?
Alain

1
@ ถึงทำไมไม่กำหนดข้อผิดพลาดเหล่านั้นที่ใช้โดยมากกว่าหนึ่งคลาสในโมดูลข้อยกเว้น / ข้อผิดพลาด แต่ปล่อยให้คนอื่น ๆ ทั้งหมดที่กำหนดไว้ในชั้นเดียวที่ใช้พวกเขา?
Scott W

@ScottW ในกรณีนี้เราต้องพึ่งพานักพัฒนาซอฟต์แวร์เพื่อทำการตรวจสอบ
Josh Saint Jacque

22

ในทางรถไฟคุณสามารถทำapp/errorsไดเรกทอรี

# app/errors/foo_error.rb
class FooError < StandardError; end

รีสตาร์ทสปริง / เซิร์ฟเวอร์และควรรับ


ฉันจะเพิ่มข้อยกเว้นเหล่านี้ได้อย่างไร
Nikhil Wagh

@NikhilWagh อย่างใดอย่างหนึ่ง raise FooError, "Example message..."หรือraise FooError.new("Example message...")
schpet

13

นี่เป็นคำถามเก่า แต่ฉันต้องการแบ่งปันวิธีที่ฉันจัดการข้อผิดพลาดที่กำหนดเองใน Rails รวมถึงการแนบข้อความแสดงข้อผิดพลาดการทดสอบและวิธีจัดการกับActiveRecordโมเดลนี้

การสร้างข้อผิดพลาดที่กำหนดเอง

class MyClass
  # create a custome error
  class MissingRequirement < StandardError; end

  def my_instance_method
    raise MyClass::MissingRequirement, "My error msg" unless true   
  end
end

การทดสอบ (เล็กที่สุด)

test "should raise MissingRequirement if ____ is missing"
  # should raise an error
  error = assert_raises(MyClass::MissingRequirement) {
    MyClass.new.my_instance_method
  }

  assert error.message = "My error msg"
end

ด้วย ActiveRecord

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

def MyModel < ActiveRecord::Base
  validate :code_does_not_contain_hyphens

  def code_does_not_contain_hyphens
    errors.add(:code, "cannot contain hyphens") if code.include?("-")
  end
end

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

หวังว่านี่จะช่วยได้!


9

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

นี่คือวิธีที่ฉันติดตั้งข้อผิดพลาดในโครงการล่าสุด:

ใน lib/app_name/error/base.rb

module AppName
    module Error
        class Base < StandardError; end
    end
end

และในข้อผิดพลาดที่กำหนดเองที่ตามมาเช่นใน lib/app_name/error/bad_stuff.rb

module AppName
    module Error
        class BadStuff < ::AppName::Error::Base; end
    end
end

จากนั้นคุณควรจะสามารถโทรหาข้อผิดพลาดของคุณผ่าน:

 raise AppName::Error::BadStuff.new("Bad stuff just happened")

และหากคุณไม่ต้องการไฟล์แยกต่างหากสำหรับข้อผิดพลาดใหม่แต่ละข้อให้ใส่ทั้งหมดไว้ lib/app_name/error.rb
jlhonora

กำลังรับ uninitialized constant MyController::AppNameได้รับฉันเรียกการเพิ่มในตัวควบคุมของฉัน
Nikhil Wagh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.