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

คู่มือการเปลี่ยนจากโหมด "classic" เป็นโหมด "zeitwerk"

คู่มือนี้เอกสารถึงวิธีการย้ายแอปพลิเคชัน Rails จากโหมด "classic" เป็นโหมด "zeitwerk"

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

Chapters

  1. โหมด "classic" และโหมด "zeitwerk" คืออะไร?
  2. เหตุผลที่ต้องเปลี่ยนจากโหมด "classic" เป็นโหมด "zeitwerk"?
  3. ฉันกลัว
  4. วิธีเปิดใช้โหมด "zeitwerk"
  5. วิธีการตรวจสอบแอปพลิเคชันว่าทำงานในโหมด zeitwerk หรือไม่?
  6. แอปพลิเคชันของฉันเป็นไปตามกฎระเบียบของ Zeitwerk หรือไม่?
  7. ตรวจสอบการปฏิบัติตาม Zeitwerk ในชุดทดสอบ
  8. ลบการเรียกใช้ require
  9. คุณสามารถใช้คุณลักษณะใหม่ได้

1 โหมด "classic" และโหมด "zeitwerk" คืออะไร?

ตั้งแต่ต้นเริ่มและจนถึง Rails 5, Rails ใช้ autoloader ที่ได้รับการนำเสนอใน Active Support โหมดนี้เรียกว่า "classic" และยังคงใช้ได้ใน Rails 6.x แต่ Rails 7 ไม่รวม autoloader นี้อีกต่อไป

เริ่มต้นด้วย Rails 6, Rails จัดส่งพร้อมกับวิธีการโหลดอัตโนมัติใหม่และดีกว่า ซึ่งจะมอบหมายงานให้กับ Zeitwerk gem นี้คือโหมด "zeitwerk" โดยค่าเริ่มต้นแอปพลิเคชันที่โหลดเฟรมเวิร์ก 6.0 และ 6.1 ทำงานในโหมด "zeitwerk" และนี่เป็นโหมดเดียวที่มีใน Rails 7

2 เหตุผลที่ต้องเปลี่ยนจากโหมด "classic" เป็นโหมด "zeitwerk"?

autoloader โหมด "classic" มีประโยชน์อย่างมาก แต่มีปัญหาบางอย่างที่ทำให้การโหลดอัตโนมัติเป็นเรื่องที่ยากและสับสนบ้างครั้ง Zeitwerk ถูกพัฒนาขึ้นเพื่อแก้ไขปัญหานี้ รวมถึงแรงบันดาลใจอื่น ๆ ด้วย

เมื่ออัปเกรดไปยัง Rails 6.x แนะนำให้เปลี่ยนเป็นโหมด "zeitwerk" เพราะเป็น autoloader ที่ดีกว่า โหมด "classic" ถูกยกเลิกใช้

Rails 7 จะสิ้นสุดระยะเวลาการเปลี่ยนแปลงและไม่รวมโหมด "classic" อีกต่อไป

3 ฉันกลัว

ไม่ต้องกลัว :)

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

คู่มือนี้จะช่วยคุณเปลี่ยน autoloader โดยมั่นใจ

หากเพราะเหตุใดก็ตามคุณพบสถานการณ์ที่คุณไม่รู้วิธีแก้ไข อย่าลังเลที่จะ เปิดปัญหาใน rails/rails และแท็ก @fxn

4 วิธีเปิดใช้โหมด "zeitwerk"

4.1 แอปพลิเคชันที่ทำงานด้วย Rails 5.x หรือต่ำกว่า

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

4.2 แอปพลิเคชันที่ทำงานด้วย Rails 6.x

ในแอปพลิเคชันที่ทำงานด้วย Rails 6.x มีสองสถานการณ์

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

# config/application.rb
config.load_defaults 6.0
config.autoloader = :classic # ลบบรรทัดนี้

อย่างที่กล่าวไว้เพียงแค่ลบการแทนที่ โหมด "zeitwerk" เป็นค่าเริ่มต้น

ในทางกลับกันหากแอปพลิเคชันกำลังโหลดค่าเริ่มต้นเก่าคุณต้องเปิดใช้โหมด "zeitwerk" โดยชัดเจน:

# config/application.rb
config.load_defaults 5.2
config.autoloader = :zeitwerk

4.3 แอปพลิเคชันที่ทำงานด้วย Rails 7

ใน Rails 7 มีเพียงโหมด "zeitwerk" เท่านั้น คุณไม่ต้องทำอะไรเพื่อเปิดใช้งาน ใน Rails 7 นั้น setter config.autoloader= ไม่มีอยู่จริงๆ ถ้า config/application.rb ใช้มัน กรุณาลบบรรทัดนั้น

5 วิธีการตรวจสอบแอปพลิเคชันว่าทำงานในโหมด zeitwerk หรือไม่?

เพื่อตรวจสอบว่าแอปพลิเคชันทำงานในโหมด zeitwerk หรือไม่ ให้รันคำสั่ง

bin/rails runner 'p Rails.autoloaders.zeitwerk_enabled?'

ถ้าพิมพ์ true ออกมา แสดงว่าโหมด zeitwerk เปิดใช้งาน

6 แอปพลิเคชันของฉันเป็นไปตามกฎระเบียบของ Zeitwerk หรือไม่?

6.1 config.eager_load_paths

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

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

config.autoload_paths << "#{Rails.root}/extras"

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

config.autoload_paths << "#{Rails.root}/extras"
config.eager_load_paths << "#{Rails.root}/extras"

6.2 zeitwerk:check

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

bin/rails zeitwerk:check

ผลการตรวจสอบที่ประสบความสำเร็จจะมีลักษณะดังนี้:

% bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!

อาจมีผลลัพธ์เพิ่มเติมขึ้นอยู่กับการกำหนดค่าแอปพลิเคชัน แต่ "All is good!" ที่สุดคือผลลัพธ์ที่คุณต้องการ

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

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

ถ้ามีค่าคงที่หนึ่งรายการที่รายงาน ให้แก้ไขรายการนั้นและรันงานอีกครั้ง ทำซ้ำจนกว่าคุณจะได้ผลลัพธ์ "All is good!"

เช่น:

% bin/rails zeitwerk:check
Hold on, I am eager loading the application.
expected file app/models/vat.rb to define constant Vat

VAT เป็นภาษีของยุโรป ไฟล์ app/models/vat.rb กำหนดค่า VAT แต่ autoloader คาดหวัง Vat ทำไม?

6.3 คำย่อ

นี่เป็นประเภทที่พบบ่อยที่สุดของความไม่สอดคล้อง มันเกี่ยวกับคำย่อ มาเรียนรู้ว่าทำไมเราจึงได้รับข้อความผิดพลาดนั้น

autoloader แบบคลาสสิกสามารถโหลด VAT เพราะข้อมูลนำเข้าของมันคือชื่อค่าคงที่ที่ขาดหายไป VAT จะเรียกใช้ underscore บนมันซึ่งจะให้ผลลัพธ์เป็น vat และมองหาไฟล์ที่ชื่อ vat.rb มันทำงาน

ข้อมูลนำเข้าของ autoloader ใหม่คือระบบไฟล์ โดยให้ Zeitwerk เรียกใช้ camelize บน vat ซึ่งจะให้ผลลัพธ์เป็น Vat และคาดหวังให้ไฟล์กำหนดค่าคงที่ Vat นั่นคือสิ่งที่ข้อความผิดพลาดกล่าวถึง

การแก้ไขปัญหานี้ง่าย เพียงแค่บอก inflector เกี่ยวกับคำย่อนี้:

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym "VAT"
end

การทำเช่นนี้จะมีผลต่อวิธีการเปลี่ยนรูปคำทั่วโลกของ Active Support อาจจะเป็นไปได้ แต่ถ้าคุณต้องการคุณยังสามารถส่งการแทนที่ไปยัง inflector ที่ใช้โดย autoloader ได้เช่นกัน ```ruby

config/initializers/zeitwerk.rb

Rails.autoloaders.main.inflector.inflect("vat" => "VAT") ```

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

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

6.4 ข้อกังวล

คุณสามารถโหลดและโหลดแบบกระจายจากโครงสร้างมาตรฐานด้วยไดเรกทอรีย่อย concerns เช่น

app/models
app/models/concerns

โดยค่าเริ่มต้น app/models/concerns เป็นส่วนหนึ่งของเส้นทางการโหลดและดังนั้นถือว่าเป็นไดเรกทอรีราก ดังนั้น โดยค่าเริ่มต้น app/models/concerns/foo.rb ควรจะกำหนด Foo ไม่ใช่ Concerns::Foo

หากแอปพลิเคชันของคุณใช้ Concerns เป็นเนมสเปซ คุณมีตัวเลือกสองอย่าง:

  1. ลบเนมสเปซ Concerns จากคลาสและโมดูลเหล่านั้นและอัปเดตโค้ดไคลเอ็นต์
  2. ปล่อยให้สิ่งที่เป็นไปได้โดยการลบ app/models/concerns จากเส้นทางการโหลดแบบกระจาย:
  # config/initializers/zeitwerk.rb
  ActiveSupport::Dependencies.
    autoload_paths.
    delete("#{Rails.root}/app/models/concerns")

6.5 มี app ในเส้นทางการโหลดแบบกระจาย

บางโปรเจกต์ต้องการสิ่งที่เหมือนกับ app/api/base.rb เพื่อกำหนด API::Base และเพิ่ม app เข้าไปในเส้นทางการโหลดแบบกระจายเพื่อทำให้เป็นไปได้

เนื่องจาก Rails จะเพิ่มไดเรกทอรีย่อยทั้งหมดของ app เข้าสู่เส้นทางการโหลดแบบอัตโนมัติ (กับข้อยกเว้นบางอย่าง) เราจึงมีสถานการณ์อีกหนึ่งที่มีไดเรกทอรีรากที่ซ้อนกัน เหมือนกับสิ่งที่เกิดขึ้นกับ app/models/concerns การตั้งค่านี้จะไม่ทำงานอีกต่อไป

อย่างไรก็ตาม คุณสามารถเก็บโครงสร้างนั้นไว้ได้ เพียงแค่ลบ app/api ออกจากเส้นทางการโหลดแบบกระจายในไฟล์เริ่มต้น:

# config/initializers/zeitwerk.rb
ActiveSupport::Dependencies.
  autoload_paths.
  delete("#{Rails.root}/app/api")

ระวังเรื่องไดเรกทอรีย่อยที่ไม่มีไฟล์ที่จะโหลดแบบกระจาย / โหลดแบบกระจาย เช่น หากแอปพลิเคชันมี app/admin พร้อมกับทรัพยากรสำหรับ ActiveAdmin คุณต้องละเว้นการโหลดแบบกระจายของพวกเขาเช่นกัน เช่นเดียวกับ assets และเพื่อนๆ:

# config/initializers/zeitwerk.rb
Rails.autoloaders.main.ignore(
  "app/admin",
  "app/assets",
  "app/javascripts",
  "app/views"
)

โดยไม่ตั้งค่าดังกล่าวแอปพลิเคชันจะโหลดแบบกระจายพวกนั้น จะเกิดข้อผิดพลาดใน app/admin เนื่องจากไฟล์ของมันไม่ได้กำหนดค่าคงที่ และจะกำหนดโมดูล Views เป็นตัวอย่างที่ไม่ต้องการเป็นผลข้างเคียง

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

6.6 ค่าคงที่ที่โหลดแบบกระจายและเนมสเปซที่ระบุโดยชัดแจ้ง

หากมีเนมสเปซที่ระบุในไฟล์ เช่น Hotel ที่นี่:

app/models/hotel.rb         # กำหนด Hotel
app/models/hotel/pricing.rb # กำหนด Hotel::Pricing

ค่าคงที่ Hotel ต้องถูกกำหนดโดยใช้คีย์เวิร์ด class หรือ module เช่น:

class Hotel
end

ถูกต้อง

การเลือกทางเลือกอื่น เช่น

Hotel = Class.new

หรือ

Hotel = Struct.new

จะไม่ทำงาน อ็อบเจกต์ลูกเช่น Hotel::Pricing จะไม่พบ

ข้อจำกัดนี้ใช้เฉพาะเนมสเปซที่ระบุโดยชัดแจ้ง เท่านั้น คลาสและโมดูลที่ไม่กำหนดเนมสเปซสามารถกำหนดได้โดยใช้รูปแบบเหล่านั้น

6.7 ไฟล์หนึ่งไฟล์หนึ่งค่าคงที่ (ในระดับบนเดียวกัน)

ในโหมด classic คุณสามารถกำหนดค่าคงที่หลายค่าในระดับบนเดียวกันและให้โหลดใหม่ทั้งหมดได้ เช่น โดยให้

class A
end

class B
end
# app/models/foo.rb

class Foo
end

class Bar
end

ในขณะที่ Bar ไม่สามารถโหลดอัตโนมัติได้ การโหลดอัตโนมัติ Foo จะทำให้ Bar ถูกทำเครื่องหมายว่าโหลดอัตโนมัติด้วย

นี่ไม่ใช่กรณีในโหมด zeitwerk คุณจำเป็นต้องย้าย Bar ไปยังไฟล์ของตัวเอง bar.rb หนึ่งไฟล์หนึ่งค่าคงที่ด้านบน

สิ่งนี้มีผลเฉพาะค่าคงที่ในระดับบนเดียวกันเช่นในตัวอย่างด้านบน คลาสและโมดูลภายในจะไม่มีปัญหา ตัวอย่างเช่นพิจารณา

# app/models/foo.rb

class Foo
  class InnerClass
  end
end

หากแอปพลิเคชันโหลด Foo อีกครั้ง จะโหลด Foo::InnerClass อีกครั้งด้วย

6.8 การใช้ Globs ใน config.autoload_paths

ระวังการกำหนดค่าที่ใช้เครื่องหมาย * อย่างเช่น

config.autoload_paths += Dir["#{config.root}/extras/**/"]

ทุกส่วนของ config.autoload_paths ควรแทนที่เนมสเปซระดับบน (Object) นั่นจะไม่ทำงาน

ในการแก้ไขปัญหานี้ เพียงเอาเครื่องหมาย * ออก:

config.autoload_paths << "#{config.root}/extras"

6.9 การตกแต่งคลาสและโมดูลจากเอ็นจิน

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

config.to_prepare do
  Dir.glob("#{Rails.root}/app/overrides/**/*_override.rb").sort.each do |override|
    require_dependency override
  end
end

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

overrides = "#{Rails.root}/app/overrides"
Rails.autoloaders.main.ignore(overrides)
config.to_prepare do
  Dir.glob("#{overrides}/**/*_override.rb").sort.each do |override|
    load override
  end
end

6.10 before_remove_const

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

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

class Country < ActiveRecord::Base
  def self.before_remove_const
    expire_redis_cache
  end
end

เป็น

# config/initializers/country.rb
if Rails.application.config.reloading_enabled?
  Rails.autoloaders.main.on_unload("Country") do |klass, _abspath|
    klass.expire_redis_cache
  end
end

6.11 Spring และ Environment test

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

# config/environments/test.rb
config.cache_classes = false

หรือตั้งแต่ Rails 7.1:

# config/environments/test.rb
config.enable_reloading = true

มิฉะนั้น คุณจะได้รับ:

reloading is disabled because config.cache_classes is true

หรือ

reloading is disabled because config.enable_reloading is false

สิ่งนี้ไม่มีผลกระทบต่อประสิทธิภาพ

6.12 Bootsnap

โปรดตรวจสอบว่าคุณได้รับการขึ้นอยู่กับ Bootsnap เวอร์ชัน 1.4.4 ขึ้นไป

7 ตรวจสอบการปฏิบัติตาม Zeitwerk ในชุดทดสอบ

งาน zeitwerk:check มีประโยชน์ในขณะที่กำลังย้าย หลังจากที่โครงการเป็นไปตามมาตรฐานแล้ว แนะนำให้ทำการตรวจสอบนี้อัตโนมัติ ในการทำเช่นนี้ การโหลดแอปพลิเคชันอย่างรวดเร็วเพียงพอ ซึ่งเป็นสิ่งที่ zeitwerk:check ทำจริงๆ

7.1 การสร้างความสัมพันธ์ต่อเนื่อง

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

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

# config/environments/test.rb
config.eager_load = ENV["CI"].present?

ตั้งแต่ Rails 7 เริ่มต้นแอปพลิเคชันที่สร้างขึ้นใหม่จะถูกกำหนดค่าเช่นนั้นโดยค่าเริ่มต้น

7.2 ชุดทดสอบเบา

หากโครงการของคุณไม่มีการรวมต่อเนื่อง คุณยังสามารถโหลดชุดทดสอบเบาๆ ได้โดยเรียกใช้ Rails.application.eager_load!:

7.2.1 Minitest

require "test_helper"

class ZeitwerkComplianceTest < ActiveSupport::TestCase
  test "โหลดไฟล์ทั้งหมดโดยไม่มีข้อผิดพลาด" do
    assert_nothing_raised { Rails.application.eager_load! }
  end
end

7.2.2 RSpec

require "rails_helper"

RSpec.describe "การปฏิบัติตาม Zeitwerk" do
  it "โหลดไฟล์ทั้งหมดโดยไม่มีข้อผิดพลาด" do
    expect { Rails.application.eager_load! }.not_to raise_error
  end
end

8 ลบการเรียกใช้ require

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

ในแอปพลิเคชัน Rails คุณใช้ require ในการโหลดโค้ดจาก lib หรือจากบุคคลที่สามเช่น gem dependencies หรือ standard library อย่าโหลดโค้ดแอปพลิเคชันที่สามารถโหลดอัตโนมัติได้ด้วย require ดูว่าทำไมนี่เป็นไอเดียที่ไม่ดีแล้วในโหมด classic ที่นี่.

require "nokogiri" # ดี
require "net/http" # ดี
require "user"     # ไม่ดี, ลบส่วนนี้ (ถ้ามี app/models/user.rb)

โปรดลบการเรียกใช้ require ของประเภทนี้ทั้งหมด

9 คุณสามารถใช้คุณลักษณะใหม่ได้

9.1 ลบการเรียกใช้ require_dependency

ทุกกรณีที่รู้จักของ require_dependency ถูกกำจัดด้วย Zeitwerk คุณควรค้นหาในโปรเจกต์และลบมัน

หากแอปพลิเคชันของคุณใช้ Single Table Inheritance โปรดดูส่วน Single Table Inheritance ของเรื่อง Autoloading and Reloading Constants (Zeitwerk Mode) guide.

9.2 ชื่อที่มีคุณสมบัติในการกำหนดค่าคลาสและโมดูล

คุณสามารถใช้เส้นทางคงที่ในการกำหนดค่าคลาสและโมดูลได้อย่างเข้มแข็ง:

# Autoloading ในส่วนของคลาสนี้ตรงกับเซมันติกของ Ruby ตอนนี้
class Admin::UsersController < ApplicationController
  # ...
end

สิ่งที่ควรระวังคือ ขึ้นอยู่กับลำดับการดำเนินการ โหลดโค้ดแบบคลาสิกอาจสามารถโหลด Foo::Wadus ใน

class Foo::Bar
  Wadus
end

ซึ่งไม่ตรงกับเซมันติกของ Ruby เนื่องจาก Foo ไม่ได้อยู่ในการซ้อนกัน และจะไม่ทำงานเลยในโหมด zeitwerk หากคุณพบกรณีเช่นนี้คุณสามารถใช้ชื่อที่มีคุณสมบัติ Foo::Wadus:

class Foo::Bar
  Foo::Wadus
end

หรือเพิ่ม Foo เข้าไปในการซ้อนกัน:

module Foo
  class Bar
    Wadus
  end
end

9.3 ความปลอดภัยของเธรดทุกที่

ในโหมด classic การโหลดค่าคงที่ไม่ปลอดภัยสำหรับเธรด แต่ Rails มีการล็อคเพื่อทำให้การร้องขอเว็บปลอดภัยสำหรับเธรด

การโหลดค่าคงที่ปลอดภัยสำหรับเธรดในโหมด zeitwerk ตัวอย่างเช่น คุณสามารถโหลดอัตโนมัติในสคริปต์ที่ใช้หลายเธรดที่ถูกดำเนินการโดยคำสั่ง runner

9.4 การโหลดแบบกระจายและโหลดอัตโนมัติเป็นความสอดคล้องกัน

ในโหมด classic หาก app/models/foo.rb กำหนด Bar คุณจะไม่สามารถโหลดไฟล์นั้นได้ แต่การโหลดแบบกระจายจะทำงานเนื่องจากโหลดไฟล์แบบลูกโซ่โดยไม่คำนึงถึงอะไร สิ่งนี้อาจเป็นแหล่งกำเนิดของข้อผิดพลาดหากคุณทดสอบสิ่งที่โหลดแบบกระจายก่อน การดำเนินการอาจล้มเหลวในการโหลดอัตโนมัติในภายหลัง

ในโหมด zeitwerk ทั้งการโหลดแบบกระจายและโหลดอัตโนมัติเป็นความสอดคล้องกัน พวกเขาล้มเหลวและมีข้อผิดพลาดในไฟล์เดียวกัน

ข้อเสนอแนะ

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

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

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

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

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