रेल्स ट्यूटोरियल्स खत्म करने और अपना खुद का ऐप शुरू करने के बाद, चीजें भ्रमित हो जाती हैं। जैसे आपका नॉन-CRUD, सामान्य लॉजिक कहां जाता है? ट्विटर से फॉलोअर्स लेना MVC में कैसे फिट बैठता है? दो लोगों से पूछें, और आपको चार उत्तर मिलेंगे। या आपका थ्रेड घंटों तक एक-दूसरे का अपमान करने वाले स्मार्ट लोगों में बदल जाता है, जबकि आप अपना सिर डेस्क पर पीटते हैं। किसी भी तरह, आपको सिरदर्द रह जाता है।
आप कुछ सामान्य, नॉन-रेल्स लॉजिक के बिना वह ऐप नहीं बना सकते जिसका आप सपना देख रहे हैं। तो आप अपना कोड कहां रखते हैं, और फिर भी चीजों को सरल रखते हैं?
शुरू करने के लिए आसान जगह
जब मेरे पास लॉजिक होता है जो मौजूदा एक्टिवरिकॉर्ड मॉडल से संबंधित महसूस होता है, तो मैं इसे उस मॉडल में रखकर शुरू करूंगा। उदाहरण के लिए, अगर मेरे पास एक Game मॉडल होता और मैं CSV फाइलों से गेम्स का एक समूह आयात करना चाहता, तो मैं उस मेथड को सीधे Game क्लास पर रखूंगा:
class Game < ActiveRecord::Base
def self.parse_from_csv(csv_string)
games = []
CSV.parse(csv_string, quote_char: "'") do |row|
games << Game.from_csv_row(row) if (row[0] == 'G')
end
games
end
def self.from_csv_row(row)
Game.new({
dgs_game_id: row[1],
opponent_name: row[2],
created_at: row[4],
updated_at: row[4],
})
end
end
आपके पास आपके मेथड्स को जिन जानकारियों की आवश्यकता होती है, वे सब हाथ में हैं। यह आसानी से टेस्टेबल है। और यह शायद वह जगह है जहां एक नया योगदानकर्ता उस लॉजिक को पहले ढूंढेगा।
लेकिन अगर आप उस मॉडल को जोड़ते और बदलते रहते हैं, तो यह बड़ा और जटिल हो जाएगा। मॉडल के विभिन्न भाग अजीब तरीकों से इंटरैक्ट करेंगे। जितना अधिक आप इसे बदलते हैं, उतना ही कठिन इसे बदलना होगा।
उस स्थिति में, आप शायद उस कोड को नॉन-एक्टिवरिकॉर्ड मॉडल में रीफैक्टर करना चाहेंगे।
नॉन-एक्टिवरिकॉर्ड मॉडल्स
सिर्फ इसलिए कि यह एक रेल्स ऐप में है, इसका मतलब यह नहीं है कि इसे एक्टिव/एक्शन-जो भी से विरासत में मिलना होगा।
आप अपना खुद का रूबी कोड, प्लेन रूबी ऑब्जेक्ट्स में लिख सकते हैं, और उन्हें अपने रेल्स ऐप में उपयोग कर सकते हैं। इन ऑब्जेक्ट्स को अभी भी मॉडल्स कहा जा सकता है, क्योंकि वे आपकी समस्या के एक हिस्से को मॉडल कर रहे हैं। उनके पास बस उनके डेटा को स्टोर करने वाला एक्टिवरिकॉर्ड डेटाबेस नहीं है।
अगली बार जब मैंने उस गेम CSV पार्सर पर काम किया, तो Game क्लास थोड़ी बहुत बड़ी हो रही थी। इसलिए मैंने पार्सर लॉजिक को अपनी खुद की GameCSVParser क्लास में स्थानांतरित कर दिया।
पूरा कमिट यहां है, लेकिन यह है कि नॉन-एक्टिवरिकॉर्ड क्लास कैसी दिखती है:
class GameCSVParser
def initialize(csv_string)
@rows = CSV.parse(csv_string, quote_char: "'")
end
def games
game_rows.map { |row| Game.new(game_attributes(row)) }
end
private
def game_rows
@rows.select { |row| is_game_row?(row) }
end
def game_attributes(row)
{
dgs_game_id: row[1],
opponent_name: row[2],
created_at: row[4],
updated_at: row[4],
}
end
def is_game_row?(row)
row[0] == 'G'
end
end
मैं सीधे एक नया प्लेन रूबी ऑब्जेक्ट बनाने जाऊंगा यदि मैं जो लॉजिक जोड़ रहा हूं वह किसी विशिष्ट एक्टिवरिकॉर्ड मॉडल से संबंधित महसूस नहीं होता। या अगर कोड ऐसा लगता है कि यह किसी ऐसी चीज का हिस्सा होना चाहिए जो अभी तक ऐप में मौजूद नहीं है। अन्यथा, वे ज्यादातर रीफैक्टरिंग के माध्यम से सामने आते हैं।
प्लेन रूबी ऑब्जेक्ट्स के साथ, आप कुछ भी लिख सकते हैं। लेकिन यह जानना कि आप कुछ भी लिख सकते हैं, दिशा के साथ आपकी मदद नहीं करता। आपको किन मेथड्स की आवश्यकता है? आपके सभी नए ऑब्जेक्ट्स कैसे इंटरैक्ट करेंगे?
बहुत सारे रेल्स ऐप्स प्लेन रूबी ऑब्जेक्ट्स की समान कैटेगरीज़ का उपयोग करते हैं। ये पैटर्न हैं जिनका पालन करके आप कोड लिख सकते हैं जिसे अन्य डेवलपर्स पहचानेंगे। आपने उनमें से कुछ के बारे में पहले ही सुना होगा।
सर्विस ऑब्जेक्ट्स, प्रेजेंटर्स, और जॉब्स
सर्विस ऑब्जेक्ट्स, प्रेजेंटर्स, और जॉब्स के बारे में कुछ खास नहीं है। वे सिर्फ प्लेन रूबी ऑब्जेक्ट्स हैं जो एक विशेष पहचानने योग्य तरीके से कार्य करते हैं।
उदाहरण के लिए, एक रेस्क्यू जॉब एक प्लेन रूबी क्लास है जिसमें एक perform मेथड और एक @queue होता है:
class FetchGamesForPlayer
@queue = :default
def self.perform(player_id)
player = Player.scoped_by_id(player_id).ready_for_fetching.first
player && player.fetch_new_games!
end
end
perform तब कॉल किया जाता है जब जॉब चलाया जाता है।
एक प्रेजेंटर एक प्लेन रूबी ऑब्जेक्ट है जिसमें कोड होता है जो केवल व्यू के अंदर समझ में आता है:
class UserPresenter
def show_related_users?
@user.related.count > 3
end
end
यह रेल्स के व्यू हेल्पर्स को भी शामिल कर सकता है, या कुछ अलग ऑब्जेक्ट्स ले सकता है और उन्हें व्यू की सुविधा के लिए एक एकीकृत ऑब्जेक्ट के रूप में मान सकता है।
एक सर्विस ऑब्जेक्ट एक प्लेन रूबी ऑब्जेक्ट है जो एक प्रक्रिया का प्रतिनिधित्व करता जिसे आप करना चाहते हैं। उदाहरण के लिए, एक पोस्ट पर कमेंट लिखना हो सकता है:
- कमेंट छोड़ें।
- पोस्ट के लेखक को एक नोटिफिकेशन मेल भेजें।
एक सर्विस ऑब्जेक्ट दोनों कर सकता है, और उस लॉजिक को आपके कंट्रोलर से बाहर रख सकता है।
सर्विस ऑब्जेक्ट्स पर एक बेहतरीन लेख यहां है। यह उदाहरणों से भरा है।
सरल प्रक्रियाओं के लिए, मैं सर्विस ऑब्जेक्ट्स की जहमत नहीं उठाता। लेकिन अगर कंट्रोलर बहुत भारी होने लगे, तो वे उस अतिरिक्त लॉजिक को रखने के लिए एक अच्छी जगह हैं।
आप अपने बिजनेस लॉजिक को व्यवस्थित करने के लिए इन पैटर्न का उपयोग कर सकते हैं। वे सिर्फ प्लेन रूबी ऑब्जेक्ट्स हैं, लेकिन वे ऐसे रूबी ऑब्जेक्ट्स हैं जो एक निश्चित स्वाद साझा करते हैं, जिनका एक नाम है, और जिनके बारे में आप अन्य डेवलपर्स से बात कर सकते हैं।
आप कहां से शुरू करते हैं?
आपके नॉन-रेल्स बिजनेस लॉजिक के लिए बहुत सारी अलग-अलग जगहें हैं। चुनना कठिन हो सकता है। तो यहां मैं क्या करता हूं:
- यदि लॉजिक ज्यादातर किसी मौजूदा क्लास से संबंधित है, भले ही वह एक्टिवरिकॉर्ड मॉडल हो, तो मैं इसे उस क्लास में रखता हूं।
- यदि यह किसी मौजूदा क्लास में फिट नहीं होता, तो मैं लॉजिक को रखने के लिए एक नया प्लेन रूबी क्लास बनाता हूं।
- यदि ऐसा लगता है कि लॉजिक किसी ऐसी चीज का हिस्सा होना चाहिए जो अभी तक मौजूद नहीं है, तो मैं इसके लिए एक नया प्लेन रूबी क्लास बनाता हूं।
- यदि मैं बाद में कोड पर वापस आता हूं, और मॉडल बहुत जटिल हो रहा है, या कोड अब उस मॉडल में समझ में नहीं आता, तो मैं इसे अपने खुद के प्लेन रूबी क्लास में रीफैक्टर करूंगा।
- यदि कोड केवल व्यू में समझ में आता है, तो मैं इसे हेल्पर में जोड़ूंगा या एक प्रेजेंटर बनाऊंगा।
- यदि कोड को HTTP रिक्वेस्ट के दौरान चलने की आवश्यकता नहीं है, या पृष्ठभूमि में चलना है, तो यह जॉब में जाता है।
- यदि मैं कई अलग-अलग मॉडल्स या प्रक्रिया के चरणों को संभाल रहा हूं, और यह कंट्रोलर को समझने में बहुत कठिन बना रहा है, तो मैं इसे सर्विस ऑब्जेक्ट में डालूंगा।
आपके बारे में क्या? आपका कोड कहां जाता है? और क्या इनके अलावा कोई पैटर्न हैं जो आपने मददगार पाए हैं? एक कमेंट छोड़ें और मुझे बताएं।
और यदि आपके पास अभी तक कोई प्रक्रिया नहीं है, तो मेरा प्रयास करें। देखें कि यह आपको कैसे फिट बैठता है। कोड लिखने का कोई सही तरीका नहीं है, लेकिन जब आप अटक जाते हैं, तो इस तरह की प्रक्रिया आपको शुरू करने में मदद करेगी।