Ruby on Rails
वर्ग संगठन
खोज…
टिप्पणियों
ऐसा करना एक साधारण बात लगती है, लेकिन जब आप कक्षाएं आकार में गुब्बारा करने लगते हैं तो आप आभारी होंगे कि आपने उन्हें व्यवस्थित करने के लिए समय लिया।
मॉडल वर्ग
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates :user, presence: true
validates :title, presence: true, length: { in: 6..40 }
scope :topic, -> (topic) { joins(:topics).where(topic: topic) }
before_save :update_slug
after_create :send_welcome_email
def publish!
update(published_at: Time.now, published: true)
end
def self.find_by_slug(slug)
find_by(slug: slug)
end
private
def update_slug
self.slug = title.join('-')
end
def send_welcome_email
WelcomeMailer.welcome(self).deliver_now
end
end
मॉडल आमतौर पर इसके लिए जिम्मेदार होते हैं:
- संबंध स्थापित करना
- मान्य डेटा
- स्कोप और विधियों के माध्यम से डेटा तक पहुंच प्रदान करना
- डेटा की दृढ़ता के आसपास क्रिया करना।
उच्चतम स्तर पर, मॉडल डोमेन अवधारणाओं का वर्णन करते हैं और उनकी दृढ़ता का प्रबंधन करते हैं।
सेवा वर्ग
नियंत्रक हमारे आवेदन का एक प्रवेश बिंदु है। हालाँकि, यह एकमात्र संभव प्रवेश बिंदु नहीं है। मैं अपने तर्क को यहां से सुलभ करना चाहूंगा:
- रेक कार्य
- पृष्ठभूमि की नौकरियां
- कंसोल
- परीक्षण
अगर मैं अपने तर्क को एक नियंत्रक में फेंक दूं तो यह इन सभी स्थानों से सुलभ नहीं होगा। तो चलो "पतला नियंत्रक, वसा मॉडल" का प्रयास करें और तर्क को एक मॉडल में स्थानांतरित करें। लेकिन कौन सा? यदि दिए गए तर्कों में User
, Cart
और Product
मॉडल शामिल हैं - इसे कहां रहना चाहिए?
एक वर्ग जो ActiveRecord::Base
से विरासत में मिला है ActiveRecord::Base
पहले से ही बहुत सारी जिम्मेदारियां हैं। यह क्वेरी इंटरफ़ेस, संघों और मान्यताओं को संभालता है। यदि आप अपने मॉडल में और भी अधिक कोड जोड़ते हैं तो यह जल्दी से सैकड़ों सार्वजनिक तरीकों के साथ एक अप्रत्याशित गड़बड़ हो जाएगा।
एक सेवा सिर्फ एक नियमित रूबी वस्तु है। इसकी कक्षा को किसी विशिष्ट वर्ग से विरासत में प्राप्त नहीं होना है। इसका नाम एक क्रिया वाक्यांश, उदाहरण के लिए है CreateUserAccount
बजाय UserCreation
या UserCreationService
। यह ऐप / सर्विसेज डायरेक्टरी में रहता है। आपको यह निर्देशिका स्वयं बनानी होगी, लेकिन आपके लिए रेलें ऑटोलैड क्लासेस के अंदर होंगी।
एक सेवा वस्तु एक काम करती है
एक सेवा ऑब्जेक्ट (उर्फ विधि ऑब्जेक्ट) एक क्रिया करता है। यह उस क्रिया को करने के लिए व्यावसायिक तर्क रखता है। यहाँ एक उदाहरण है:
# app/services/accept_invite.rb
class AcceptInvite
def self.call(invite, user)
invite.accept!(user)
UserMailer.invite_accepted(invite).deliver
end
end
मैं जिन तीन सम्मेलनों का अनुसरण करता हूं, वे हैं:
सेवाएँ app/services directory
अंतर्गत जाती हैं। मैं आपको व्यावसायिक तर्क-भारी डोमेन के लिए उपनिर्देशिका का उपयोग करने के लिए प्रोत्साहित करता हूं। उदाहरण के लिए:
- फ़ाइल
app/services/invite/accept.rb
Invite::Accept
app/services/invite/accept.rb
को परिभाषित करेगाInvite::Accept
app/services/invite/accept.rb
कोInvite::Accept
हुएInvite::Accept
app/services/invite/create.rb
Invite::Create
- सेवाएं एक क्रिया से शुरू होती हैं (और सेवा के साथ समाप्त नहीं होती हैं):
ApproveTransaction
,SendTestNewsletter
,ImportUsersFromCsv
- सेवाएँ
call
विधि का जवाब देती हैं। मैंने पाया कि एक और क्रिया का उपयोग करने से यह थोड़ा बेमानी हो जाता है:ApproveTransaction.approve()
अच्छी तरह से नहीं पढ़ता है। इसके अलावा,call
विधिlambda
,procs
और विधि ऑब्जेक्ट्स के लिए वास्तविक विधि है।
लाभ
सेवा ऑब्जेक्ट दिखाते हैं कि मेरा आवेदन क्या करता है
मैं तो बस सेवाओं निर्देशिका पर नज़र देखने के लिए क्या कर सकते हैं अपने आवेदन करता है: ApproveTransaction
, CancelTransaction
, BlockAccount
, SendTransactionApprovalReminder
...
एक सेवा वस्तु में एक त्वरित नज़र और मुझे पता है कि व्यापार तर्क क्या शामिल है। मुझे नियंत्रकों, ActiveRecord
मॉडल कॉलबैक और पर्यवेक्षकों के माध्यम से जाने की ज़रूरत नहीं है कि यह समझने के लिए कि "लेनदेन को मंजूरी देना" क्या शामिल है।
क्लीन-अप मॉडल और कंट्रोलर
नियंत्रकों ने अनुरोधों (पैरामेट्स, सत्र, कुकीज़) को तर्कों में बदल दिया, उन्हें सेवा में नीचे भेज दिया और सेवा की प्रतिक्रिया के अनुसार पुनर्निर्देशित या प्रस्तुत किया।
class InviteController < ApplicationController
def accept
invite = Invite.find_by_token!(params[:token])
if AcceptInvite.call(invite, current_user)
redirect_to invite.item, notice: "Welcome!"
else
redirect_to '/', alert: "Oopsy!"
end
end
end
मॉडल केवल संघों, स्कोप, मान्यताओं और दृढ़ता के साथ व्यवहार करते हैं।
class Invite < ActiveRecord::Base
def accept!(user, time=Time.now)
update_attributes!(
accepted_by_user_id: user.id,
accepted_at: time
)
end
end
यह परीक्षण करने और बनाए रखने के लिए मॉडल और नियंत्रकों को बहुत आसान बनाता है!
सर्विस क्लास का उपयोग कब करें
जब कोई कार्रवाई इनमें से एक या अधिक मानदंडों को पूरा करती है, तो सेवा ऑब्जेक्ट के लिए पहुंचें:
- कार्रवाई जटिल है (जैसे एक लेखांकन अवधि के अंत में पुस्तकों को बंद करना)
- कार्रवाई कई मॉडलों में पहुंचती है (उदाहरण के लिए, ऑर्डर, क्रेडिट कार्ड और ग्राहक वस्तुओं का उपयोग करके ई-कॉमर्स खरीद)
- कार्रवाई एक बाहरी सेवा (जैसे सामाजिक नेटवर्क पर पोस्टिंग) के साथ सहभागिता करती है
- कार्रवाई अंतर्निहित मॉडल की एक मुख्य चिंता नहीं है (जैसे एक निश्चित समय अवधि के बाद पुराने डेटा को स्वीप करना)।
- कार्रवाई करने के कई तरीके हैं (जैसे एक एक्सेस टोकन या पासवर्ड के साथ प्रमाणित करना)।
सूत्रों का कहना है