2010-07-09 14 views
5

में किसी ऑब्जेक्ट की कक्षा को बदलना मान लें कि मेरे पास एक डेटाबेस तालिका में FireNinja < Ninja ऑब्जेक्ट है, जो एकल तालिका विरासत का उपयोग करके संग्रहीत है। बाद में, मुझे एहसास हुआ कि वह वास्तव में WaterNinja < Ninja है। उसे विभिन्न उप-वर्ग में बदलने का सबसे साफ तरीका क्या है? इससे भी बेहतर, मुझे एक नया WaterNinja ऑब्जेक्ट बनाना अच्छा लगेगा और आईडी को संरक्षित करने वाले डीबी में पुराने FireNinja को प्रतिस्थापित करें।ActiveRecord

संपादित मैं से नए WaterNinja वस्तु बनाने के लिए कैसे पता अपने मौजूदा FireNinja, और मैं भी मैं पुराने हट जाए और नया एक को बचा सकता है पता है। मैं क्या करना चाहता हूं मौजूदा आइटम की कक्षा उत्परिवर्तित करना है। चाहे मैं एक नई ऑब्जेक्ट बनाकर और कुछ ActiveRecord जादू को पंक्ति को प्रतिस्थापित करने के लिए करता हूं, या ऑब्जेक्ट के लिए कुछ प्रकार की पागल चीज कर रहा हूं, या यहां तक ​​कि इसे हटाकर और उसी आईडी के साथ पुन: सम्मिलित करके प्रश्न का हिस्सा है।

उत्तर

2

आप दो काम करने होंगे:

  • WaterNinja < Ninja
  • बनाएं ninjas तालिका कुछ चलाने में तरह UPDATE ninjas SET (type = 'WaterNinja') WHERE (type = 'FireNinja')

इसके बारे में है।

रनटाइम रूपांतरण करने के लिए यह ऐसा करेगा, लेकिन मैं अनुशंसा नहीं करता हूं।

class Ninja 
    def become_another_ninja(new_ninja_type) 
    update_attribute(:type, new_ninja_type) 
    self.class.find(id) 
    end 
end 

@water_ninja = @fire_ninja.become_another_ninja('WaterNinja') 

इस के साथ समस्या यह है कि @fire_ninja अब एक throwaway वस्तु हो जाएगा।

+0

ऐसा लगता है कि आप जवाब दे रहे हैं, "मैं सभी 'फायर निंजा' को 'वॉटरनिंज' में कैसे बदलूं?" जवाब अभी भी काम करता है हालांकि अगर मैं स्थिति को 'आईडी = myid' में बदलता हूं। हाँ, मैंने उस बारे में सोचा था।मुझे कुछ वॉटरनिंज-विशिष्ट फ़ील्ड सेटिंग करने के लिए अद्यतन के बाद वस्तु को खींचना होगा, लेकिन यह ठीक है। मैं कुछ थोड़ा क्लीनर की उम्मीद कर रहा था, हालांकि। –

+0

मैं देखता हूं कि आपका क्या मतलब है। मैं ऐसा करने की अनुशंसा नहीं करता, लेकिन यह चाल करेगा: 'ninja_id = @ ninja.id; @ ninja.update_attribute (: प्रकार, 'वाटरनिंज'); @ninja = WaterNinja.find (ninja_id) ' –

+0

मैंने वर्णित विधि को दिखाने के लिए संपादित किया। –

-1

आपको WaterNinja#to_fireninja विधि को परिभाषित करना होगा। रूबी को एक ही वस्तु को रखने के दौरान किसी ऑब्जेक्ट की कक्षा को बदलने का कोई तरीका नहीं है।

class WaterNinja < Ninja 
    def to_fireninja 
    FireNinja.new :name => name 
    end 
end 
+0

यह नई वस्तु बनाएगा, लेकिन जब मैं सहेजता हूं, तो यह डेटाबेस में एक अलग पंक्ति बना देगा। मैं अपने नए वॉटरनिजा ऑब्जेक्ट के साथ फायरनिंजा के अपने निरंतर उदाहरण को प्रतिस्थापित करना चाहता हूं। –

+0

@Isaac: मुझे नहीं लगता कि यह संभव है, जब तक कि आप वॉटरनिंजा को हटा नहीं सकते और ActiveRecord को उसी आईडी के साथ नया फ़ायरनिंज सहेजने के लिए मजबूर नहीं कर सकते। – Adrian

+0

एक तरफ सवाल का उत्तर दिया जा सकता है अगर आप मुझे बता सकते हैं कि मौजूदा आईडी के साथ नया निंजा कैसे बचाया जाए। मुझे हटाने और पुनः सम्मिलित करने में खुशी होगी। –

0

विरासत पर रचना का अनुकूलन - आपको रनटाइम पर इस प्रकार के व्यवहार को बदलने के लिए रणनीति पैटर्न का उपयोग करना चाहिए।

http://en.wikipedia.org/wiki/Strategy_pattern

+0

जरूरी नहीं है। Google "पॉलिमॉर्फिज्म के साथ प्रतिस्थापित करें" और "रणनीति के साथ प्रतिस्थापित करें" पैटर्न को प्रतिबिंबित करने के लिए। रणनीति का उपयोग कुछ मामलों को कवर करता है, लेकिन दूसरों में विरासत पसंद करेंगे। इन पैटर्न को रेफैक्टरिंग में भी अच्छी तरह से वर्णित किया गया है (http://www.amazon.com/Refactoring-Ruby-Jay-Fields/dp/0321603508) पुस्तक। – samuil

+0

मेरे पास उपरोक्त प्रस्तुत की गई समस्या से स्वतंत्र विरासत का उपयोग करने के अच्छे कारण हैं। मैं changetypeofninja.com नहीं बना रहा हूँ। –

7

आप

@ninja.becomes(WaterNinja) 

करके एक WaterNinja के रूप में अपने FireNinja कार्य कर सकते हैं आप स्थायी रूप से कक्षाओं में बदल करना चाहते हैं, तो बस प्रकार विशेषता के ऊपर लिख सकते हैं।

@ninja.type = "WaterNinja" 
@ninja.save! 
+0

यह सही उत्तर है, स्वीकृत उत्तर उतना अच्छा नहीं है क्योंकि यह "बनने" का उपयोग नहीं करता है – Rob