2009-07-14 14 views
31

अपडेट के लिए टिप्पणियां देखें।रेल: कई बहुलक संबंधों में से कई

मैं इस पर एक स्पष्ट और सीधा-आगे जवाब पाने के लिए संघर्ष कर रहा हूं, मुझे आशा है कि इस बार मुझे यह मिल जाएगा! : डी मुझे निश्चित रूप से रेल के साथ सीखने के लिए बहुत कुछ है, हालांकि मैं जिस समस्या का सामना कर रहा हूं उसे समझता हूं और वास्तव में अतिरिक्त सहायता की सराहना करता हूं।

  • मेरे पास "टास्क" नामक एक मॉडल है।
  • मेरे पास "लक्ष्य" नामक एक अमूर्त मॉडल है।
  • मैं लक्ष्य से कार्य के उप-वर्गों के कई उदाहरणों को जोड़ना चाहता हूं।
  • मैं एकल तालिका विरासत का उपयोग नहीं कर रहा हूं।
  • मैं लक्ष्य के उप-वर्गों के एक मिश्रित परिणाम सेट को वापस करने के लिए बहुलक संबंधों से पूछताछ करना चाहता हूं।
  • मैं उन कार्यों को प्राप्त करने के लिए लक्ष्य के उप-वर्गों के व्यक्तिगत उदाहरणों से पूछना चाहता हूं जिनके साथ वे संबंध हैं।

तो, मुझे लक्ष्य के कार्य और उप-वर्गों के बीच कई रिश्तों के लिए एक बहुरूप पोलिमोर्फिक लगता है। और अधिक विस्तार में, मैं सांत्वना (और निश्चित रूप से कहीं और) में इस तरह काम करने के लिए सक्षम हो जाएगा:

task = Task.find(1) 
task.targets 
[...array of all the subclasses of Target here...] 

लेकिन! मान लिया जाये कि मॉडल "स्टोर", "सॉफ़्टवेयर", "कार्यालय", "वाहन" है, जो "लक्ष्य" के लिए मौजूद सभी उपवर्गों हैं, यह अच्छा होगा भी दूसरी दिशा में संबंध पार करने के लिए:

store = Store.find(1) 
store.tasks 
[...array of all the Tasks this Store is related to...] 
software = Software.find(18) 
software.tasks 
[...array of all the Tasks this Software is related to...] 

डेटाबेस बहुरूपी रिश्तों से गर्भित टेबल इस ट्रेवर्सल करने में सक्षम हो गया लगता है, लेकिन मैं एक जवाब जो मेरे लिए बहुरूपी रिश्तों की भावना को हराने खोजने की कोशिश में कुछ आवर्ती विषयों देखें:

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

यह रेल की कार्यक्षमता या सामूहिक समुदाय ज्ञान में एक छोटा छेद प्रतीत होता है। तो उम्मीद है कि stackoverflow जवाब के लिए मेरी खोज chronicle कर सकते हैं!

मदद करने वाले हर किसी के लिए धन्यवाद!

+0

अपने छह बुलेट बिंदुओं में, उनमें से पांच "मैं एकल तालिका वंशानुक्रम का उपयोग नहीं कर रहा हूँ" अगर आप छठे ड्रॉप प्राप्त करने के लिए तुच्छ कर रहे हैं। नीचे एसटीआई पर अपने बिंदु के बारे में, क्योंकि अतिरिक्त कॉलम वास्तव में आपको बग करते हैं, अतिरिक्त मॉडलों और अन्य मॉडलों के व्यवहार को धक्का देने के लिए प्रतिनिधिमंडल का उपयोग करने पर विचार करें। – austinfromboston

+2

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

+0

मैं has_many_polymorphs के उपयोग के माध्यम से इच्छित अधिकांश कार्यक्षमताओं को पूरा करने में सक्षम हूं। एक शेष सीमा यह है कि मैं अभी भी अपने माता-पिता (कार्य) में प्रत्येक बहुलक प्रकार को परिभाषित कर रहा हूं। अतिरिक्त समाधानों का स्वागत है, लेकिन मुझे यकीन नहीं है कि रेलवे के नए संस्करण या has_many_polymorphs के अपडेट तक एक समाधान हमारे ऊपर होगा! –

उत्तर

0

यह विशेष रूप से सहायक उत्तर नहीं हो सकता है, लेकिन बस कहा गया है, मुझे नहीं लगता कि ऐसा करने का एक आसान या स्वचालित तरीका है। कम से कम, सरल या एक से कई संगठनों के साथ आसान नहीं है।

मुझे लगता है कि जॉइन टेबल के लिए एक ActiveRecord मॉडल बनाना समस्या से संपर्क करने का सही तरीका है। एक सामान्य has_and_belongs_to_many संबंध एक, दो निर्दिष्ट तालिकाओं के बीच में शामिल होने मानता जबकि आपके मामले में यह लग रहा है जैसे आप tasks और stores में से किसी एक, softwares, offices, या vehicles (वैसे बीच में शामिल करना चाहते हैं, वहाँ एक कारण एसटीआई उपयोग करने के लिए नहीं है यहाँ? ऐसा लगता है जैसे यह आपके पास टेबल की संख्या सीमित करके जटिलता को कम करने में मदद करेगा)। तो आपके मामले में, जॉइन टेबल को Target उपclass के नाम को भी जानने की आवश्यकता होगी। जैसे

create_table :targets_tasks do |t| 
    t.integer :target_id 
    t.string :target_type 
    t.integer :task_id 
end 

फिर, अपने Task कक्षा में, अपने Target उपवर्गों, और TargetsTask वर्ग कुछ है, आप के रूप में ActiveRecord::Associations::ClassMethods rdoc pages पर प्रलेखित :through कीवर्ड का उपयोग has_many संघों सेट कर सकते हैं।

लेकिन फिर भी, यह आपको केवल रास्ते का हिस्सा बनता है, क्योंकि :through फ़ील्ड को Target सबक्लास नाम के रूप में उपयोग करने के बारे में नहीं पता होगा। इसके लिए, आप कुछ कस्टम चयन/खोजक एसक्यूएल टुकड़े लिखने में सक्षम हो सकते हैं, ActiveRecord::Associations::ClassMethods में भी दस्तावेज किए गए हैं।

उम्मीद है कि यह आपको सही दिशा में आगे बढ़ता है। अगर आपको पूरा समाधान मिल जाए, तो मुझे यह देखना अच्छा लगेगा!

+0

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

+0

इसके अलावा, मैं एसटीआई का उपयोग नहीं कर रहा हूं क्योंकि यह अक्षम है और जिस तरह से मैं अपना डेटा स्टोर करना चाहता हूं। मैं डिफ़ॉल्ट रूप से ऊपर और परे लक्ष्य के उप-वर्गों के साथ अतिरिक्त व्यवहार जोड़ रहा हूं।बहुत सारे कॉलम वाली बड़ी टेबलें मुझसे अपील नहीं करती हैं :) –

0

मैं दूसरों मैं एक समाधान एसटीआई का एक मिश्रण का उपयोग करता है और प्रतिनिधिमंडल लागू करने के लिए आसान होगा कि के लिए जाना होगा के साथ सहमत हैं।

आपकी समस्या के केंद्र में लक्ष्य के सभी उप-वर्गों का रिकॉर्ड स्टोर करना है। ActiveRecord एसटीआई मॉडल के माध्यम से डेटाबेस चुनता है।

आप लक्ष्य में एक वर्ग चर में संग्रहीत और इसे करने के लिए नए लोगों को जोड़ने के लिए विरासत में मिला कॉलबैक इस्तेमाल कर सकते हैं। फिर आप उस सरणी और लीवरेज method_missing की सामग्री से आवश्यक कोड को गतिशील रूप से उत्पन्न कर सकते हैं।

0

आपको लगता है कि पीछा जानवर बल दृष्टिकोण है:

class Task 
    has_many :stores 
    has_many :softwares 
    has_many :offices 
    has_many :vehicles 

    def targets 
    stores + softwares + offices + vehicles 
    end 
    ... 

यह नहीं हो सकता है कि सुरुचिपूर्ण, लेकिन ईमानदारी से यह है कि अत्यधिक शब्द नहीं है, और स्वाभाविक कोड के बारे में अक्षम कोई बात नहीं है।

+0

दाएं, लेकिन फिर कार्य को प्रत्येक प्रकार के लक्ष्य के बारे में पता होना चाहिए। मैं एक लक्ष्य बनाने योग्य बनने में सक्षम होना चाहता हूं और जब भी कोई नया जोड़ा जाता है तो कार्य को संशोधित करने की आवश्यकता नहीं होती है। –

+0

यह रूबी है। आप अपने स्टोर, कार्यालय इत्यादि में शामिल होने के लिए "belong_to_task" क्लास विधि (या एक मॉड्यूल) लिख सकते हैं। यह कार्य वर्ग को संशोधित कर सकता है, जो ऊपर किया गया है (एक है_मनी जोड़ना और कक्षा को शामिल करने के लिए लक्ष्य को पैच करना) । मैं उस दृष्टिकोण की सिफारिश नहीं कर रहा हूं, मैं बस कह रहा हूं ... – ndp

53

आप बहुरूपता को जोड़ सकते हैं और has_many :through एक लचीला मानचित्रण पाने के लिए:

class Assignment < ActiveRecord::Base 
    belongs_to :task 
    belongs_to :target, :polymorphic => true 
end 

class Task < ActiveRecord::Base 
    has_many :targets, :through => :assignment 
end 

class Store < ActiveRecord::Base 
    has_many :tasks, :through => :assignment, :as => :target 
end 

class Vehicle < ActiveRecord::Base 
    has_many :tasks, :through => :assignment, :as => :target 
end 

... और बहुत आगे है।

+2

यह समस्या को हल करने के लिए बहुत ही सरल लगता है और 100% रेल द्वारा समर्थित है। –

+0

स्वच्छ और सरल – brettish

+1

ध्यान दें कि ': as => target' दोनों मामलों में': =>: target' होना चाहिए। अच्छा समाधान –

1

आपके द्वारा उल्लेख किया गया है has_many_polymorphs समाधान बुरा नहीं है।

class Task < ActiveRecord::Base 
    has_many_polymorphs :targets, :from => [:store, :software, :office, :vehicle] 
end 

जो कुछ भी आप चाहते हैं उसे करने के लिए लगता है।

यह निम्न विधियों प्रदान करता है:

टास्क करने के लिए:

t = Task.first 
t.targets # Mixed collection of all targets associated with task t 
t.stores # Collection of stores associated with task t 
t.softwares # same but for software 
t.offices # same but for office 
t.vehicles # same but for vehicles 

सॉफ्टवेयर, स्टोर, कार्यालय, वाहन के लिए:

s = Software.first # works for any of the subtargets. 
s.tasks    # lists tasks associated with s 

मैं सही ढंग से टिप्पणी अनुसरण कर रहा हूँ, तो केवल शेष समस्या यह है कि जब भी आप एक नया प्रकार का उप-लक्ष्य बनाते हैं तो आप ऐप/मॉडल/task.rb को संशोधित नहीं करना चाहते हैं। ऐसा लगता है कि रेलवे तरीके से आपको दो फाइलें संशोधित करने की आवश्यकता होती है ताकि बिडरेक्शनल एसोसिएशन बनाया जा सके। has_many_polymorphs केवल आपको कार्य फ़ाइल को बदलने की आवश्यकता है। मुझे जीत की तरह लगता है। या कम से कम ऐसा होगा अगर आपको नई मॉडल फ़ाइल को संपादित करने की आवश्यकता नहीं है।

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

उप-लक्ष्य की एक सूची रखें, मैं lib/subtargets में सुझाव देने जा रहा हूं जो प्रति पंक्ति एक प्रविष्टि स्वरूपित है अनिवार्य रूप से table_name.underscore। (कैपिटल अक्षरों एक अंडरस्कोर पहले से जुड़ा हुआ है और फिर सब कुछ किया जाता है लोअरकेस)

store 
software 
office 
vehicle 

config/initializers/subtargets.rb बनाएं और इस के साथ इसे भरने:

SubtargetList = File.open("#{RAILS_ROOT}/lib/subtargets").read.split.reject(&:match(/#/)).map(&:to_sym) 

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

क्षमा करें, मैं वास्तव में अब यह सही माध्यम से चलने की तरह नहीं लग रहा है, लेकिन यहाँ someresources

अंत में सूची has_many_polymorphs घोषणा में SubtargetList

class Task < ActiveRecord::Base 
    has_many_polymorphs :targets, :from => SubtargetList 
end 

साथ इस बिंदु से पर की जगह हैं आप

$ script/generate subtarget_model home 

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

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

1

एसटीआई का उपयोग करना:

class Task < ActiveRecord::Base 
end 

class StoreTask < Task 
    belongs_to :store, :foreign_key => "target_id" 
end 

class VehicleTask < Task 
    belongs_to :vehicle, :foreign_key => "target_id" 
end 

class Store < ActiveRecord::Base 
    has_many :tasks, :class_name => "StoreTask", :foreign_key => "target_id" 
end 

class Vehicle < ActiveRecord::Base 
    has_many :tasks, :class_name => "VehicleTask", :foreign_key => "target_id" 
end 

अपने databse में आप की आवश्यकता होगी: Task type:string और Task target_id:integer

लाभ यह है कि अब आप प्रत्येक कार्य के प्रकार है जो विशिष्ट हो सकता है के लिए मॉडल के माध्यम से एक है।

भी देखें STI and polymorphic model together

चीयर्स!

10

हालांकि इस सवाल का जवाब SFEley द्वारा द्वारा प्रस्तावित महान है, वहाँ एक कुछ खामियां:

  • लक्ष्य (स्टोर/वाहन) से कार्यों की बहाली से काम करता है, लेकिन अभ्यस्त पीछे की ओर। यह मूल रूप से है क्योंकि आप एक बहुलक डेटा प्रकार से एसोसिएशन के माध्यम से नहीं जा सकते हैं क्योंकि एसक्यूएल यह नहीं बता सकता कि यह किस तालिका में है।
  • एसोसिएशन के माध्यम से प्रत्येक मॉडल को मध्यवर्ती तालिका
  • के साथ सीधा संबंध की आवश्यकता है
  • : के माध्यम से असाइनमेंट संघ बहुवचन
  • में होना चाहिए: के रूप में बयान अभ्यस्त के साथ मिलकर काम: के माध्यम से, आप सीधे संघ मध्यवर्ती मेज
इसे ध्यान में रखते

साथ की जरूरत के साथ पहली बार यह निर्दिष्ट करने की आवश्यकता, मेरा सबसे सरल समाधान होगा:

class Assignment < ActiveRecord::Base 
    belongs_to :task 
    belongs_to :target, :polymorphic => true 
end 

class Task < ActiveRecord::Base 
    has_many :assignments 
    # acts as the the 'has_many targets' needed 
    def targets 
    assignments.map {|x| x.target} 
    end 
end 

class Store < ActiveRecord::Base 
    has_many :assignments, as: :target 
    has_many :tasks, :through => :assignment 
end 

class Vehicle < ActiveRecord::Base 
    has_many :assignments, as: :target 
    has_many :tasks, :through => :assignment, :as => :target 
end 

संदर्भ: http://blog.hasmanythrough.com/2006/4/3/polymorphic-through

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