2009-07-01 14 views
234

मैं वास्तव में रेल का आनंद ले रहा हूं (भले ही मैं आम तौर पर रीस्टलेस हूं), और मुझे रूबी बहुत ओओ का आनंद मिलता है। फिर भी, विशाल ActiveRecord उपclass और विशाल नियंत्रकों को बनाने की प्रवृत्ति काफी प्राकृतिक है (भले ही आप प्रति संसाधन नियंत्रक का उपयोग करें)। यदि आप गहरी वस्तु दुनिया बनाना चाहते थे, तो आप कक्षाओं (और मॉड्यूल, मुझे लगता है) कहां रखा जाएगा? मैं विचारों के बारे में पूछ रहा हूं (हेल्पर्स में खुद?), नियंत्रक और मॉडल।रेल में ओओ डिज़ाइन:

लीब ठीक है, और मुझे some solutions to get it to reload in a dev environment मिला है, लेकिन मुझे यह जानना है कि क्या यह सामान करने का बेहतर तरीका है। मैं वास्तव में बहुत बड़ी कक्षाओं के बारे में चिंतित हूं। इसके अलावा, इंजन के बारे में क्या और वे कैसे फिट बैठते हैं?

उत्तर

371

चूंकि रेल एमवीसी के संदर्भ में संरचना प्रदान करते हैं, इसलिए का उपयोग करके मॉडल, व्यू, और नियंत्रक कंटेनर का उपयोग करना आपके लिए उपलब्ध है। शुरुआती (और यहां तक ​​कि कुछ मध्यवर्ती प्रोग्रामर) के लिए सामान्य मुहावरे ऐप में मॉडल (डेटाबेस क्लास), नियंत्रक, या दृश्य में सभी तर्क को क्रैक करना है।

किसी बिंदु पर, कोई व्यक्ति "वसा-मॉडल, पतला-नियंत्रक" प्रतिमान को इंगित करता है, और मध्यवर्ती डेवलपर्स जल्द ही अपने नियंत्रकों से सब कुछ उत्पादित करते हैं और इसे मॉडल में फेंक देते हैं, जो एप्लिकेशन तर्क के लिए एक नया कचरा बनना शुरू कर देता है ।

स्कीनी नियंत्रक वास्तव में एक अच्छा विचार हैं, लेकिन सिद्धांत - मॉडल में सब कुछ डालने, वास्तव में सबसे अच्छी योजना नहीं है।

रूबी में, आपके पास चीजों को अधिक मॉड्यूलर बनाने के लिए कुछ अच्छे विकल्प हैं। एक काफी लोकप्रिय जवाब केवल मॉड्यूल का उपयोग करना है (आमतौर पर lib में रखा गया है) जिसमें विधियों के समूह हैं, और फिर उचित कक्षाओं में मॉड्यूल शामिल हैं। यह उन मामलों में सहायता करता है जहां आपके पास कार्यक्षमता की श्रेणियां हैं जिन्हें आप कई कक्षाओं में पुन: उपयोग करना चाहते हैं, लेकिन जहां कार्यक्षमता अभी भी कक्षाओं से जानबूझकर जुड़ी हुई है।

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

यह समाधान कुछ मामलों में अच्छी तरह से काम कर सकता है - अन्य मामलों में, आप अपने कोड में कक्षाओं का उपयोग करने के बारे में सोचना चाहते हैं जो मॉडल, विचार या नियंत्रक नहीं हैं।

इसके बारे में सोचने का एक अच्छा तरीका "एकल जिम्मेदारी सिद्धांत" है, जो कहता है कि एक वर्ग को एक (या छोटी संख्या) चीजों के लिए ज़िम्मेदार होना चाहिए। आपके मॉडल डेटाबेस से डेटा तक लगातार डेटा के लिए ज़िम्मेदार हैं। आपके नियंत्रक अनुरोध प्राप्त करने और व्यवहार्य प्रतिक्रिया लौटने के लिए ज़िम्मेदार हैं।

आप अवधारणाओं है कि उन बक्से (हठ, अनुरोध/प्रतिक्रिया प्रबंधन) में बड़े करीने से फिट नहीं है है, तो आप शायद के बारे में सोचना चाहते कि कैसे आप होगा मॉडल प्रश्न में विचार। आप कहीं और एप्लिकेशन/कक्षाओं में गैर मॉडल वर्गों स्टोर कर सकते हैं, या, और ऐसा करके अपनी लोड पथ के लिए उस निर्देशिका जोड़ें:

config.load_paths << File.join(Rails.root, "app", "classes") 

आप यात्री या JRuby प्रयोग कर रहे हैं, तो आप शायद भी अपने को जोड़ना चाहते हैं उत्सुक लोड पथ के लिए पथ:

config.eager_load_paths << File.join(Rails.root, "app", "classes") 

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

अद्यतन: यह उत्तर रेल 2.x और उच्चतर पर लागू होता है।

+0

डी ओह। गैर-मॉडल के लिए एक अलग निर्देशिका जोड़ना मेरे लिए नहीं हुआ था। मैं एक साफ-सुथरा महसूस कर रहा हूं ... –

+0

येहुदा, इसके लिए धन्यवाद। बहुत बढ़िया जवाब।यह वही है जो मैं अपने द्वारा प्राप्त किए गए ऐप्स (और जो मैं करता हूं) में देख रहा हूं: नियंत्रकों, विचारों, विचारों और नियंत्रकों और विचारों के लिए स्वचालित रूप से प्रदान किए गए सहायक उपकरण में सबकुछ। फिर मिश्रण से libins आओ, लेकिन वास्तविक ओओ मॉडलिंग करने का कोई प्रयास कभी नहीं किया है। आप सही हैं, यद्यपि: "ऐप्स/कक्षाओं, या कहीं और में।" सिर्फ यह जांचना चाहता था कि क्या कुछ मानक उत्तर है जो मुझे याद आ रहा है ... –

+33

हाल के संस्करणों के साथ, config.autoload_paths ऐप के अंतर्गत सभी निर्देशिकाओं के लिए डिफ़ॉल्ट है। इसलिए आपको ऊपर वर्णित config.load_paths को बदलने की आवश्यकता नहीं है। मैं eager_load_paths (अभी तक) के बारे में निश्चित नहीं हूं, और इसे देखने की आवश्यकता है। क्या कोई पहले से ही जानता है? –

58

अद्यतन: चिंता का उपयोग confirmed as the new default in Rails 4 रहा है।

यह वास्तव में मॉड्यूल की प्रकृति पर निर्भर करता है। मैं आम तौर पर एप के भीतर एक/चिंताओं फ़ोल्डर में नियंत्रक/मॉडल एक्सटेंशन रखता हूं।

# concerns/authentication.rb 
module Authentication 
    ... 
end  

# controllers/application_controller.rb 
class ApplicationController 
    include Authentication 
end 



# concerns/configurable.rb 
module Configurable 
    ... 
end  

class Model 
    include Indexable 
end 

# controllers/foo_controller.rb 
class FooController < ApplicationController 
    include Indexable 
end 

# controllers/bar_controller.rb 
class BarController < ApplicationController 
    include Indexable 
end 

/lib सामान्य उद्देश्य पुस्तकालयों के लिए मेरी पसंदीदा पसंद है। मेरे पास हमेशा lib में प्रोजेक्ट नेमस्पेस है जहां मैंने सभी एप्लिकेशन-विशिष्ट पुस्तकालयों को रखा है।

/lib/myapp.rb 
module MyApp 
    VERSION = ... 
end 

/lib/myapp/CacheKey.rb 
/lib/myapp/somecustomlib.rb 

रूबी/रेल कोर एक्सटेंशन आमतौर पर config initializers में जगह ले ताकि पुस्तकालयों केवल रेल बूटस्ट्रैप पर एक बार लोड किए गए हैं।

/config/initializer/config.rb 
/config/initializer/core_ext/string.rb 
/config/initializer/core_ext/array.rb 

पुन: प्रयोज्य कोड के टुकड़े के लिए, मैं अक्सर (माइक्रो) प्लगइन्स ताकि मैं उन्हें अन्य परियोजनाओं में पुन: उपयोग कर सकते हैं पैदा करते हैं।

सहायक फाइलों में आमतौर पर सहायक उपकरण (उदाहरण के लिए फॉर्म बिल्डर्स) द्वारा उपयोग किए जाने के उद्देश्य से सहायक उपकरण और कभी-कभी कक्षाएं होती हैं।

यह वास्तव में एक सामान्य अवलोकन है। यदि आप अधिक अनुकूलित सुझाव प्राप्त करना चाहते हैं तो कृपया विशिष्ट उदाहरणों के बारे में अधिक जानकारी प्रदान करें। :)

+0

विचित्र बात हो। मुझे यह आवश्यकता_ निर्भरता RAILS_ROOT + "/ lib/my_module" lib निर्देशिका से कुछ के साथ काम करने के लिए नहीं मिल सकता है। यह फ़ाइल निष्पादित नहीं होती है और शिकायत करती है, लेकिन यह इसे पुनः लोड नहीं करता है। –

+0

रुबी के लिए केवल एक बार चीजों को लोड करने की आवश्यकता होती है। यदि आप बिना शर्त लोड करना चाहते हैं, तो लोड का उपयोग करें। – Chuck

+0

इसके अलावा, यह मेरे लिए बहुत असामान्य लगता है कि आप ऐप इंस्टेंस के जीवनकाल के दौरान दो बार फ़ाइल लोड करना चाहते हैं। क्या आप कोड बना रहे हैं जैसे आप जाते हैं? – Chuck

10

... प्रवृत्ति बनाने के लिए विशाल ActiveRecord उपवर्गों और विशाल नियंत्रकों काफी स्वाभाविक है ...

"विशाल" एक चिंताजनक शब्द है ... ;-)

आपके नियंत्रक विशाल कैसे हो रहे हैं? ऐसा कुछ है जिसे आप देखना चाहिए: आदर्श रूप से, नियंत्रक पतले होना चाहिए। पतली हवा से बाहर निकलने के अंगूठे को चुनकर, मैं सुझाव दूंगा कि यदि आपके पास नियमित रूप से कोड की प्रति 5 या 6 पंक्तियां हैं, तो प्रति नियंत्रक विधि (क्रिया), तो आपके नियंत्रक शायद बहुत मोटा हो। क्या कोई डुप्लिकेशंस है जो एक सहायक फ़ंक्शन या फ़िल्टर में जा सकता है? क्या व्यापार तर्क है जिसे मॉडल में धकेल दिया जा सकता है?

आपके मॉडल कैसे बड़े होते हैं? क्या आप प्रत्येक वर्ग में जिम्मेदारियों की संख्या को कम करने के तरीकों की तलाश कर रहे हैं? क्या आप मिश्रित मिश्रणों में कोई सामान्य व्यवहार कर सकते हैं? या कार्यक्षमता के क्षेत्र आप सहायक कक्षाओं में प्रतिनिधि कर सकते हैं?

संपादित करें:, थोड़ा विस्तार करने के लिए कोशिश कर रहा है उम्मीद है कि बहुत बुरी तरह से कुछ भी विकृत नहीं ...

सहायकों: app/helpers में रहते हैं और ज्यादातर विचारों सरल बनाने के लिए उपयोग किया जाता है।वे या तो नियंत्रक-विशिष्ट (उस नियंत्रक के सभी दृश्यों के लिए भी उपलब्ध हैं) या आमतौर पर उपलब्ध हैं (module ApplicationHelper application_helper.rb में)।

फ़िल्टर: मान लें कि आपके पास कई क्रियाओं में कोड की एक ही पंक्ति है (अक्सर, params[:id] या इसी तरह का उपयोग करके किसी ऑब्जेक्ट का पुनर्प्राप्ति)। उस डुप्लिकेशन को पहले एक अलग विधि के लिए सारणीबद्ध किया जा सकता है और फिर कक्षा परिभाषा में फ़िल्टर घोषित करके पूरी तरह से कार्यों से बाहर किया जा सकता है, जैसे before_filter :get_objectActionController Rails Guide में सेक्शन 6 देखें घोषणात्मक प्रोग्रामिंग आपके मित्र बनें।

रिफैक्टरिंग मॉडल एक धार्मिक चीज़ का थोड़ा और अधिक है। Uncle Bob के शिष्य सुझाव देंगे, उदाहरण के लिए, आप SOLID की पांच आज्ञाओं का पालन करते हैं। जोएल & जेफ may recommend एक और, एर, "व्यावहारिक" दृष्टिकोण, हालांकि वे बाद में little more reconciled प्रतीत हुए। किसी वर्ग के भीतर एक या अधिक विधियों को ढूंढना जो उसके गुणों के स्पष्ट रूप से परिभाषित सबसेट पर काम करते हैं, उन वर्गों की पहचान करने का एक तरीका है जिन्हें आपके ActiveRecord-derived मॉडल से दोबारा प्रतिक्रिया दी जा सकती है।

रेल मॉडल को ActiveRecord :: बेस के उप-वर्ग होने की आवश्यकता नहीं है। या इसे एक और तरीके से रखने के लिए, एक मॉडल को किसी तालिका का एनालॉग होना आवश्यक नहीं है, या यहां तक ​​कि संग्रहीत किसी भी चीज़ से संबंधित नहीं है। रेलवे के सम्मेलनों के अनुसार जब तक आप अपनी फाइल को app/models में नाम दें, तब तक क्लास नाम पर कॉल #underscore को कॉल करें, यह पता लगाने के लिए कि रेल किसी भी require के बिना पाए जाएंगे।

+0

से संबंधित है सभी मायने रखता है, माइक, और आपकी चिंता के लिए धन्यवाद ... मुझे एक ऐसी परियोजना मिली है जिसमें नियंत्रकों पर कुछ विधियां थीं जो बहुत बड़ी थीं। मैंने इन्हें छोटी विधियों में तोड़ दिया है लेकिन नियंत्रक स्वयं भी "वसा" है। तो मैं जो खोज रहा हूं वह सामानों को ऑफ़लोड करने के लिए मेरे सभी विकल्प हैं। आपके उत्तर हैं, "सहायक कार्य," "फ़िल्टर," "मॉडल," "मिश्रण" और "सहायक वर्ग"। तो फिर, मैं इन चीजों को कहां रख सकता हूं? क्या मैं एक वर्ग पदानुक्रम को व्यवस्थित कर सकता हूं जो एक देव env में स्वत: लोड हो जाता है? –

1

यहाँ कि "पतली नियंत्रक" दर्शन से उत्पन्न होती हैं लगते वसा मॉडल पुनर्रचना के बारे में एक बहुत अच्छा ब्लॉग पोस्ट है:

http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

बेसिक संदेश है "फैट मॉडल से mixins निकालें मत करो", उपयोग इसके बजाय सेवा कक्षाएं, लेखक 7 पैटर्न प्रदान करता है ताकि

संबंधित मुद्दे