2009-04-16 9 views
5

मुझे लगता है कि मेरा प्रश्न सबसे अच्छा उदाहरण के रूप में वर्णित है। मान लें कि मेरे पास "थिंग" नामक एक साधारण मॉडल है और इसमें कुछ विशेषताएं हैं जो सरल डेटा प्रकार हैं। कुछ ...रेल में एक ही कक्षा के साथ कई संघों के लिए सर्वोत्तम प्रथाओं?

Thing 
    - foo:string 
    - goo:string 
    - bar:int 

यह मुश्किल नहीं है। डीबी तालिका में उन तीन विशेषताओं के साथ तीन कॉलम होंगे और मैं उन्हें @ thing.foo या @ thing.bar जैसे कुछ तक एक्सेस कर सकता हूं।

लेकिन समस्या जो मैं हल करने की कोशिश कर रहा हूं वह तब होता है जब "foo" या "goo" अब एक साधारण डेटा प्रकार में निहित नहीं हो सकता है? मान लें कि foo और goo उसी प्रकार की ऑब्जेक्ट का प्रतिनिधित्व करते हैं। यही है, वे अलग-अलग डेटा के साथ "व्हाज़िट" दोनों उदाहरण हैं। तो अब बात ऐसी लग सकती है ...

Thing 
    - bar:int 

लेकिन अब एक नया मॉडल "Whazit" है कि इस तरह दिखता है कहा जाता है ...

Whazit 
    - content:string 
    - value:int 
    - thing_id:int 

अभी तक यह सब अच्छा है नहीं है। अब वह जगह है जहां मैं फंस गया हूँ। अगर मेरे पास @thing है, तो मैं इसे व्हाज़ित के अपने 2 उदाहरणों के संदर्भ में कैसे सेट कर सकता हूं (रिकॉर्ड के लिए, "व्यवसाय नियम" यह है कि किसी भी चीज में हमेशा 2 वज़न होंगे)? यही है, मुझे यह जानने की ज़रूरत है कि मेरे पास व्हाज़िट मूल रूप से foo या goo है या नहीं। जाहिर है, मैं वर्तमान सेटअप में @ thing.foo नहीं कर सकता, लेकिन मैं आदर्श हूं।

मेरा प्रारंभिक विचार व्हाज़िट में "नाम" विशेषता जोड़ना है, इसलिए मैं अपने @thing से जुड़े व्हाटज़िट प्राप्त कर सकता हूं और फिर उस नाम से व्हाज़िट को चाहता हूं। हालांकि यह बदसूरत लगता है।

क्या कोई बेहतर तरीका है?

उत्तर

8

कुछ तरीके हैं जो आप कर सकते हैं। सबसे पहले, आप दो belongs_to/has_one संबंधों की स्थापना कर सकते हैं:

things 
    - bar:int 
    - foo_id:int 
    - goo_id:int 

whazits 
    - content:string 
    - value:int 

class Thing < ActiveRecord::Base 
    belongs_to :foo, :class_name => "whazit" 
    belongs_to :goo, :class_name => "whazit" 
end 

class Whazit < ActiveRecord::Base 
    has_one :foo_owner, class_name => "thing", foreign_key => "foo_id" 
    has_one :goo_owner, class_name => "thing", foreign_key => "goo_id" 

    # Perhaps some before save logic to make sure that either foo_owner 
    # or goo_owner are non-nil, but not both. 
end 

एक अन्य विकल्प जो एक छोटे से क्लीनर, लेकिन यह भी एक दर्द के और अधिक जब प्लगइन्स, आदि के साथ काम कर रहा है, एकल मेज विरासत है। इस मामले में आपके पास दो कक्षाएं हैं, फू और गू, लेकिन वे दोनों एक प्रकार के स्तंभ के साथ whazits तालिका में रखा जाता है जो उन्हें अलग करता है।

things 
    - bar:int 

whazits 
    - content:string 
    - value:int 
    - thing_id:int 
    - type:string 

class Thing < ActiveRecord::Base 
    belongs_to :foo 
    belongs_to :goo 
end 

class Whazit < ActiveRecord::Base 
    # .. whatever methods they have in common .. 
end 

class Foo < Whazit 
    has_one :thing 
end 

class Goo < Whazit 
    has_one :thing 
end 

दोनों ही मामलों में आप @thing.foo और @thing.goo जैसे काम कर सकें।

@thing.foo = Whazit.new 

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

@thing.foo = Foo.new 

एसटीआई समस्याओं के अपने स्वयं के सेट है, विशेष रूप से यदि आप पुराने प्लगइन और रत्न का उपयोग कर रहे हैं। आमतौर पर यह @object.class कोड कोड के साथ एक मुद्दा है जब वे वास्तव में चाहते हैं @object.base_class। जरूरी होने पर पैच करना काफी आसान है। को छोड़कर आप एक अलग वर्ग की जरूरत नहीं है,

class Thing < ActiveRecord::Base 
    has_one :foo, :class_name => "whazit", :conditions => { :name => "foo" } 
    has_one :goo, :class_name => "whazit", :conditions => { :name => "goo" } 
end 

वास्तव में, यह काफी कैसे एसटीआई काम करता है के समान है:

2

एक "नाम" को जोड़ने के साथ आपका सरल उपाय बदसूरत होने की जरूरत नहीं है।

केवल एक चीज आप जब आप एक whazit सहयोगी इस नाम स्थापित कर रही है के लिए बाहर देखने के लिए की आवश्यकता होगी। यही कारण है कि हो सकता है के रूप में सरल रूप में:

def foo=(assoc) 
    assos.name = 'foo' 
    super(assoc) 
end 
संबंधित मुद्दे