2009-03-12 7 views
198

यह this पूर्व प्रश्न है, जिसका उत्तर दिया गया था। मुझे वास्तव में पता चला कि मैं उस क्वेरी से जुड़ सकता हूं, इसलिए अब कामकाजी क्वेरीइस ActiveRecord :: ReadOnlyRecord त्रुटि का कारण क्या है?

start_cards = DeckCard.find :all, :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true] 

यह काम प्रतीत होता है। हालांकि, जब मैं इन डेककार्ड्स को किसी अन्य संगठन में स्थानांतरित करने का प्रयास करता हूं, तो मुझे ActiveRecord :: ReadOnlyRecord त्रुटि मिलती है।

यहाँ कोड

for player in @game.players 
    player.tableau = Tableau.new 
    start_card = start_cards.pop 
    start_card.draw_pile = false 
    player.tableau.deck_cards << start_card # the error occurs on this line 
end 

और प्रासंगिक मॉडल (झांकी मेज पर खिलाड़ियों कार्ड हैं)

class Player < ActiveRecord::Base 
    belongs_to :game 
    belongs_to :user 
    has_one :hand 
    has_one :tableau 
end 

class Tableau < ActiveRecord::Base 
    belongs_to :player 
    has_many :deck_cards 
end 

class DeckCard < ActiveRecord::Base 
    belongs_to :card 
    belongs_to :deck 
end 

मैं सिर्फ इस कोड के बाद एक इसी तरह की कार्रवाई कर रहा हूँ है, करने के लिए DeckCards जोड़ने खिलाड़ियों को हाथ, और वह कोड ठीक काम कर रहा है। मुझे आश्चर्य हुआ कि मुझे डेककार्ड मॉडल में belongs_to :tableau की आवश्यकता है, लेकिन यह खिलाड़ी के हाथ में जोड़ने के लिए ठीक काम करता है। मेरे पास डेककार्ड तालिका में tableau_id और hand_id कॉलम हैं।

मैंने रेल एपीआई में ReadOnlyRecord देखा, और यह विवरण से काफी कुछ नहीं कहता है।

उत्तर

275
ActiveRecord CHANGELOG से

(v1.12.0, 16 अक्टूबर, 2005):

केवल पढ़ने के रिकॉर्ड का परिचय दें। अगर आप ऑब्जेक्ट को कॉल करते हैं। तो यह ऑब्जेक्ट को केवल-पढ़ने के लिए चिह्नित करेगा और उठाएं यदि आप object.save पर कॉल करते हैं तो ReadOnlyRecord। object.readonly? रिपोर्ट करता है कि वस्तु केवल पढ़ने के लिए है या नहीं। पासिंग: readonly => किसी भी के लिए सही खोजक विधि रिकॉर्ड्स को केवल पढ़ने के लिए चिह्नित करेगा। : विकल्प में शामिल होने का अर्थ है: केवल पढ़ने के लिए, इसलिए आप इस विकल्प का उपयोग करते हैं, उसी रिकॉर्ड को सहेजने में विफल हो जाएगा। आसपास काम करने के लिए find_by_sql का उपयोग करें।

find_by_sql का प्रयोग के रूप में यह कच्चे पंक्ति/स्तंभ डेटा देता है, नहीं ActiveRecords नहीं वास्तव में एक विकल्प है। आपके पास दो विकल्प:

  1. रिकॉर्ड (हैक) में चर उदाहरण के लिए मजबूर करने के लिए झूठी @readonly के बजाय
  2. उपयोग :include => :card:join => :card

सितं, 2010 अद्यतन

के अधिकांश ऊपर अब सच नहीं है। इस प्रकार, रेल 2.3.4 और 3.0 में।0:

  • Record.find_by_sqlका उपयोग कर है एक व्यवहार्य विकल्प एक स्पष्ट :selectहै और न ही एक स्पष्ट (या खोजक-गुंजाइश-विरासत में मिला है) :readonly बिना
  • :readonly => true स्वचालित रूप से केवल मान लिया जाता है, तो :joinsनिर्दिष्ट किया गया था विकल्प (set_readonly_option!active_record/base.rb में रेल 2.3.4 के लिए to_a के कार्यान्वयन को औरमें कार्यान्वयन देखें रेल 3.0.0)
  • हालांकि, :readonly => true हमेशा स्वचालित रूप से has_and_belongs_to_many अगर में शामिल होने की मेज और :joins दो विदेशी कुंजी स्तंभों से भी अधिक है में मान लिया जाता है के लिए active_record/relation/query_methods.rb में ७२९०४१३२१० एक स्पष्ट :select बिना निर्दिष्ट किया गया था (अर्थात उपयोगकर्ता के आपूर्ति :readonly मूल्यों अनदेखी कर रहे हैं - active_record/associations/has_and_belongs_to_many_association.rb में finding_with_ambiguous_select? देखें)
  • निष्कर्ष में
  • , जब तक कि एक विशेष के साथ काम कर तालिका में शामिल होने और has_and_belongs_to_many, तो @aaronrustad के जवाब रेल 2.3.4 और 3.0.0 में ठीक लागू होता है।। अगर आप को प्राप्त करने के एक INNER JOIN (। :includes का तात्पर्य एक LEFT OUTER JOIN है, जो कम चयनात्मक और INNER JOIN की तुलना में कम कुशल है)
+0

: शामिल # प्रश्नों को कम करने में मददगार है, मुझे इसके बारे में पता नहीं था; लेकिन मैंने tableau/Deckcards एसोसिएशन को has_many में बदलकर इसे ठीक करने का प्रयास किया: के माध्यम से, और अब मुझे 'एसोसिएशन नहीं मिला' संदेश मिल रहा है; मुझे – user26270

+0

@ कोडमैन के लिए एक और प्रश्न पोस्ट करना पड़ सकता है, हां, इसमें शामिल प्रश्नों की संख्या कम हो जाएगी * और * शामिल तालिका को आपकी हालत के दायरे में लाएगा (एक प्रकार का अंतर्निहित हिस्सा आपके रिकॉर्ड को पढ़ने के रूप में चिह्नित करता है- केवल, जैसे ही यह आपके खोज में एसक्यूएल-आईएसएच को स्नीफ करता है, इसमें शामिल हैं: शामिल हों /: चयन करें IIRC – vladr

+0

'has_many: a, through =>: b' के लिए काम करने के लिए, बी एसोसिएशन भी घोषित किया जाना चाहिए , उदाहरण के लिए 'has_many: b; has_many: a,: through =>: b', मुझे आशा है कि यह आपका मामला है? – vladr

5

find_by_sql के बजाय, आप एक निर्दिष्ट कर सकते हैं चाहते

  • नहीं उपयोग :includes कार्य करें: पर चयन खोजक और फिर सब कुछ खुश ...

    start_cards = DeckCard.find :all, :select => 'deck_cards.*', :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]

  • 43

    इस रेल की हाल ही में रिलीज में परिवर्तित हो सकता है, लेकिन उचित इस समस्या को हल करने का तरीका जोड़ने के लिए है: readonly => झूठी खोजने के विकल्पों में।

    +3

    मुझे विश्वास नहीं है कि 2.3.4 के साथ कम से कम – Olly

    +2

    यह अभी भी काम करता है रेल 3.0.10, यहां मेरे अपने कोड से एक उदाहरण प्राप्त करने का एक उदाहरण है जिसमें एक है: Fundraiser.donatable.readonly (false) – Houen

    +0

    में यह 2.3.15 – TlmaK0

    167

    या रेल में (अपनी शर्तों के साथ बदलें "...") 3 आप केवल पढ़ने के लिए विधि का उपयोग कर सकते हैं:

    (Deck.joins(:card) & Card.where('...')).readonly(false) 
    
    +0

    मेरे लिए आसानी से काम करता है। –

    +1

    हम्म ... मैंने उन दोनों रेलवेकास्टों को एशियाई जानवरों पर देखा, और न ही 'रीडोनली' समारोह का उल्लेख किया। – Purplejacket

    +1

    रेल 4 पर भी काम करता है – nocache

    3

    उसे निष्क्रिय करने के लिए ...

    module DeactivateImplicitReadonly 
        def custom_join_sql(*args) 
        result = super 
        @implicit_readonly = false 
        result 
        end 
    end 
    ActiveRecord::Relation.send :include, DeactivateImplicitReadonly 
    
    +3

    के लिए देख रहा था बंदर-पैचिंग नाजुक है - नए रेल संस्करणों द्वारा बहुत आसानी से टूटा हुआ है। निश्चित रूप से अव्यवस्थित है कि अन्य समाधान हैं। – Kelvin

    15

    का चयन करें ('* एक केवल पढ़ने के लिए रिकॉर्ड * ') का उत्पादन करता है:'

    > Contact.select('*').joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly? 
    => false 
    

    बस सत्यापित करने के लिए, का चयन करें (छोड़ते हुए) रेल 3.2 में इसे ठीक करने लगता है ':

    > Contact.joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly? 
    => true 
    

    नहीं कह सकता कि मैं तर्क को समझता हूं लेकिन कम से कम यह एक त्वरित और साफ कामकाज है।

    +4

    रेल में समान बात 4. वैकल्पिक रूप से आप 'चुन सकते हैं (quoted_table_name +'। * ')' – andorov

    +1

    वह शानदार ब्रोंसन था। धन्यवाद। – Trip

    +0

    यह काम कर सकता है, लेकिन 'readonly (false)' का उपयोग करने से अधिक जटिल है – Kelvin