কম্পিউটার টিউটোরিয়াল

রেইলস স্কোপস মেনে কভার: কার্যকরভাবে রিকর্ড প্রিলোড করা

यह लेख कोरियाई में भी उपलब्ध है, सूनसांग हाँग का धन्यवाद!

रेल्स के स्कोप्स आपके द्वारा चाहने वाले रिकॉर्ड्स को ढूंढना आसान बनाते हैं:

app/models/review.rb
class Review < ActiveRecord::Base belongs_to :restaurant scope :positive, -> { where("rating > 3.0") } end
irb(main):001:0> Restaurant.first.reviews.positive.count Restaurant Load (0.4ms) SELECT `restaurants`.* FROM `restaurants` ORDER BY `restaurants`.`id` ASC LIMIT 1 (0.6ms) SELECT COUNT(*) FROM `reviews` WHERE `reviews`.`restaurant_id` = 1 AND (rating > 3.0) => 5

लेकिन अगर आप उनके साथ सावधान नहीं हैं, तो आप अपने ऐप के प्रदर्शन को गंभीर रूप से नुकसान पहुंचाएंगे।

क्यों? आप वास्तव में एक स्कोप को प्रीलोड नहीं कर सकते। इसलिए यदि आप कुछ रेस्तरां को उनकी सकारात्मक समीक्षाओं के साथ दिखाने की कोशिश करते हैं:

irb(main):001:0> restauraunts = Restaurant.first(5) irb(main):002:0> restauraunts.map do |restaurant| irb(main):003:1* "#{restaurant.name}: #{restaurant.reviews.positive.length} positive reviews." irb(main):004:1> end Review Load (0.6ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`restaurant_id` = 1 AND (rating > 3.0) Review Load (0.5ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`restaurant_id` = 2 AND (rating > 3.0) Review Load (0.7ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`restaurant_id` = 3 AND (rating > 3.0) Review Load (0.7ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`restaurant_id` = 4 AND (rating > 3.0) Review Load (0.7ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`restaurant_id` = 5 AND (rating > 3.0) => ["Judd's Pub: 5 positive reviews.", "Felix's Nightclub: 6 positive reviews.", "Mabel's Burrito Shack: 7 positive reviews.", "Kendall's Burrito Shack: 2 positive reviews.", "Elisabeth's Deli: 15 positive reviews."]

हाँ, यह एक N+1 क्वेरी है। धीमे रेल्स ऐप्स का सबसे बड़ा कारण।

लेकिन आप इसे बहुत आसानी से ठीक कर सकते हैं, अगर आप रिलेशनशिप के बारे में अलग तरीके से सोचते हैं।

स्कोप्स को असोसिएशन में बदलें

जब आप रेल्स असोसिएशन मेथड्स का उपयोग करते हैं, जैसे belongs_to और has_many, तो आपका मॉडल आमतौर पर ऐसा दिखता है:

app/models/restaurant.rb
class Restaurant < ActiveRecord::Base has_many :reviews end

लेकिन अगर आप डॉक्यूमेंटेशन देखें, तो आप देखेंगे कि वे और भी बहुत कुछ कर सकते हैं। आप उन मेथड्स में अन्य पैरामीटर पास कर सकते हैं और बदल सकते हैं कि वे कैसे काम करते हैं।

scope सबसे उपयोगful में से एक है। यह पहले वाले scope की तरह ही काम करता है:

app/models/restaurant.rb
class Restaurant < ActiveRecord::Base has_many :reviews has_many :positive_reviews, -> { where("rating > 3.0") }, class_name: "Review" end
irb(main):001:0> Restaurant.first.positive_reviews.count Restaurant Load (0.2ms) SELECT `restaurants`.* FROM `restaurants` ORDER BY `restaurants`.`id` ASC LIMIT 1 (0.4ms) SELECT COUNT(*) FROM `reviews` WHERE `reviews`.`restaurant_id` = 1 AND (rating > 3.0) => 5

अब, आप includes के साथ अपने नए असोसिएशन को प्रीलोड कर सकते हैं:

irb(main):001:0> restauraunts = Restaurant.includes(:positive_reviews).first(5) Restaurant Load (0.3ms) SELECT `restaurants`.* FROM `restaurants` ORDER BY `restaurants`.`id` ASC LIMIT 5 Review Load (1.2ms) SELECT `reviews`.* FROM `reviews` WHERE (rating > 3.0) AND `reviews`.`restaurant_id` IN (1, 2, 3, 4, 5) irb(main):002:0> restauraunts.map do |restaurant| irb(main):003:1* "#{restaurant.name}: #{restaurant.positive_reviews.length} positive reviews." irb(main):004:1> end => ["Judd's Pub: 5 positive reviews.", "Felix's Nightclub: 6 positive reviews.", "Mabel's Burrito Shack: 7 positive reviews.", "Kendall's Burrito Shack: 2 positive reviews.", "Elisabeth's Deli: 15 positive reviews."]

6 SQL कॉल के बजाय, हमने केवल दो किए।

(class_name का उपयोग करके, आप एक ही ऑब्जेक्ट के लिए कई असोसिएशन रख सकते हैं। यह काफी अक्सर काम आता है।)

डुप्लीकेशन के बारे में क्या?

यहां अभी भी एक समस्या हो सकती है। where("rating > 3.0") अब आपके Restaurant क्लास पर है। यदि आप बाद में सकारात्मक समीक्षाओं को rating > 3.5 में बदलते हैं, तो आपको इसे दो बार अपडेट करना होगा!

यह और खराब हो जाता है: यदि आप उन सभी सकारात्मक समीक्षाओं को भी प्राप्त करना चाहते हैं जो किसी व्यक्ति ने कभी छोड़ी हैं, तो आपको उस स्कोप को User क्लास पर भी डुप्लीकेट करना होगा:

app/models/user.rb
class User < ActiveRecord::Base has_many :reviews has_many :positive_reviews, -> { where("rating > 3.0") }, class_name: "Review" end

यह बहुत DRY नहीं है।

इससे बचने का एक आसान तरीका है, हालांकि। where के अंदर, आप उस positive स्कोप का उपयोग कर सकते हैं जिसे आपने Review क्लास में जोड़ा था:

app/models/restaurant.rb
class Restaurant < ActiveRecord::Base has_many :reviews has_many :positive_reviews, -> { positive }, class_name: "Review" end

इस तरह, विचार कि क्या एक समीक्षा को सकारात्मक समीक्षा बनाता है, अभी भी केवल एक जगह पर है।

स्कोप्स महान हैं। सही जगह पर, वे आपके डेटा को क्वेरी करना आसान और मजेदार बना सकते हैं। लेकिन अगर आप N+1 क्वेरी से बचना चाहते हैं, तो आपको उनके साथ सावधान रहना होगा।

तो, यदि एक स्कोप आपको परेशानी देना शुरू करता है, तो इसे एक असोसिएशन में लपेटें और इसे प्रीलोड करें। यह बहुत अधिक काम नहीं है, और यह आपको SQL कॉल का एक गुच्छा बचाएगा।

  1. রেলসের ভিতর: কীভাবে এলিগ্যান্ট এক্সেপশন পেজ কাজ করে

  2. রেলসে ফ্ল্যাশ মেসেজ মাস্টার করুন: একটি সম্পূর্ণ গাইড

  3. পাওয়ারফুল রুবি CLI টুল বিল্ড করুন: একটি স্টেপ-বাই-স্টেপ গাইড

  4. রেইলসে OmniAuth-Twitter দিয়ে টুইটার লগইন ইন্টিগ্রেট করুন: ধাপে ধাপে গাইড