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

Streamline แอป Rails: ActiveSupport Module เนื้อหา Compact สำหรับ Global Context

โดยทั่วไป global variables แย่ แตบางครั้ง global ในที่ถูกต้อง ทำให้โค้ดง่ายมาก

ใน Rails คุณอาจ set data ครั้งเดียวระหว่าง request แตใช้ในทุก layer ของแอป User ไหน request? Permission อะไร? Database connection ไหน?

ข้อมูลนี้ควร available ทั่วโค้ด ส่งทุกที่แค่ noise แตใช้ Ruby global variable หรือ class variable ก็ทำปัญหา Threads หลายตัว overwrite ได้ และกลายเป็น mess ใหญ่ และอาจมี bad data ที่ unrecoverable

คุณต้องการสิ่งที่ global แต แค่ request ของคุณ

Plain Ruby วิธี

ปกติเห็นจัดการด้วย Thread.current[] 长这样:

Thread.current[:current_user] = user 

ง่ายพอ 解决方案不錯 แตมี 2 drawbacks ใหญ่:

  1. ใครสักคนอาจ overwrite data ของคุณโดยไม่ได้ตั้งใจ

    ถ้า 2 คนเลือก key เดียวกัน? มันจะกดข้อมูลกัน gems ของตัวเอง อาจไม่ใช่ปัญหา แตถ้าเขียน gems หรือแอปใหญ่และ messy ต้องคิดถึง

  2. มันไม่ well-structured

    Thread.current[] แค่ถุงข้อมูลใหญ่ ไม่ง่ายเอกสาร ถ้าอยากรู้ดึงอะไรได้ ต้องหาว่าใส่อะไรเข้าไป

    แตถ้าใส่ global data เยอะจนนี้เป็นปัญหา คุณมีอะไรกังวลมากกว่า Thread.current[] แล้ว แต่ยังคงเป็นจุดที่ควรจำ

มี solution 好กว่า Thread.current[] ไหม? Rails เองจัดการ request-local data เยอะ และ ActiveSupport มี pattern อื่นให้ follow

Rails วิธี

ขุด ActiveSupport อาจเจอ ActiveSupport::PerThreadRegistry จากชื่อบอกได้ว่านี่คือสิ่งที่เราหา

ด้วย ActiveSupport::PerThreadRegistry ตัวอย่างก่อนจะกลายเป็น:

class RequestRegistry extend ActiveSupport::PerThreadRegistry attr_accessor :current_user, :current_permissions end RequestRegistry.current_user = user RequestRegistry.current_user # => user 

งานเพิ่มนิดหน่อย แตกับ ActiveSupport::PerThreadRegistry:

  • มีที่วางเอกสาร ใครดูคลาส จะรู้ global data ที่คาดหวัง และใช้ได้อะไร

  • ได้ API ที่ดูดี ดูเหมือนแค่ set class variables นั่นคือสิ่งที่คุณทำถ้าไม่ต้องกังวล threads

  • Data ที่ set บน class จะ namespaced ไม่ต้องกังวล RequestRegistry.current_user ชน PhoneNumberApiRegistry.current_user แยกกันสนิท

Rails ใช้ ActiveSupport::PerThreadRegistry เอง สำหรับ ActiveRecord connection handling, storing EXPLAIN queries, ActiveSupport::Notifications หาตัวอย่างดีๆ มันเองเป็นที่เริ่มต้นดี

ตอน Threads และ Requests ไม่ Match

บาง Rails servers single thread handle multiple requests หมายถึงของใน PerThreadRegistry จะค้างอยู่ request ถัดไป น่าจะไม่ใช่สิ่งที่อยาก

ทำอย่าง Rails: cleanup สิ่งใน PerThreadRegistry หลังเสร็จ ขึ้นอยู่กับอะไรที่ใส่ อาจทำอยู่แล้ว

ในคอมเมนต์ MattB แนะนำ request_store มันทำงานเหมือน Thread.current[] แตเคลียร์ตัวเองหลังแต่ละ request

เปิดประตูให้สร้าง PerRequestRegistry รวมความปลอดภัยของ request_store กับ API ของ PerThreadRegistry ถ้ามีใครทำแล้ว ผมอยากรู้!

ลองดู

Global data อาจแย่ Globals เยอะนำไปสู่ unmaintainable code

แตถ้ามีเหตุผลเก็บ data ที่ central สำหรับ request ทั้งหมด ไปไกลกว่า Thread.current[] ลอง ActiveSupport::PerThreadRegistry หรือ request_store ถ้าอื่นไม่อาจ จะทำให้จัดการ global data น้อยลงความเสี่ยง