سؤال

هذا يلي هذا قبل السؤال الذي أجاب.أنا فعلا اكتشفت يمكنني إزالة الانضمام من أن الاستعلام حتى الآن العمل الاستعلام

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

هذا ويبدو أن العمل.ومع ذلك ، عندما أحاول نقل هذه DeckCards إلى رابطة أخرى ، أحصل على 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 في DeckCard نموذج, لكنه يعمل بشكل جيد بالنسبة إضافة إلى يد اللاعب.لدي tableau_id و hand_id الأعمدة في DeckCard الجدول.

بحثت ReadOnlyRecord في القضبان api و لا أقول ما يتجاوز الوصف.

هل كانت مفيدة؟

المحلول

القضبان 2.3.3 و أقل

من ActiveRecord CHANGELOG(v1.12.0, 16 أكتوبر, 2005):

يعرض للقراءة فقط السجلات.إذا كنت استدعاء كائن.للقراءة فقط!بعد ذلك سوف علامة الكائن للقراءة فقط و رفع ReadOnlyRecord إذا كنت الاتصال الكائن.حفظ.الكائن.للقراءة فقط?التقارير ما إذا كان الكائن هو للقراءة فقط.عابر :readonly => صحيح أن أي مكتشف طريقة مارك عاد السجلات للقراءة فقط. على :ينضم الخيار الآن يعني :للقراءة فقط ، حتى إذا يمكنك استخدام هذا الخيار ، إنقاذ نفسه سجل الآن سوف تفشل. استخدام find_by_sql كمحاولة للتغلب على.

باستخدام find_by_sql هو حقا لا بديل كما يعود الخام صف/عمود ، ActiveRecords.لديك خياران:

  1. القوة على سبيل المثال متغير @readonly إلى خطأ في سجل (هاك)
  2. استخدام :include => :card بدلا من :join => :card

القضبان 2.3.4 وما فوق

معظم ما سبق لا يعد صحيحا بعد 10 سبتمبر 2012:

  • باستخدام Record.find_by_sql هو خيارا قابلا للتطبيق
  • :readonly => true تلقائيا الاستدلال فقط إذا :joins تم تحديد دون صريح :select ولا صريح (أو الباحث-نطاق-ورثت) :readonly الخيار (انظر تنفيذ set_readonly_option! في active_record/base.rb عن القضبان 2.3.4 أو تنفيذ to_a في active_record/relation.rb و من custom_join_sql في active_record/relation/query_methods.rb عن القضبان 3.0.0)
  • ومع ذلك ، :readonly => true دائما تلقائيا في الاستدلال has_and_belongs_to_many إذا كان الانضمام إلى الجدول يحتوي على أكثر من اثنين المفاتيح الخارجية والأعمدة :joins كان المحدد دون صريح :select (أيالموفر من قبل المستخدم :readonly يتم تجاهل القيم-انظر finding_with_ambiguous_select? في active_record/associations/has_and_belongs_to_many_association.rb.)
  • في الختام ، ما لم يكن التعامل مع خاص الانضمام إلى الجدول ، has_and_belongs_to_many, ثم @aaronrustad's الجواب ينطبق على ما يرام في القضبان 2.3.4 و 3.0.0.
  • هل لا استخدام :includes إذا كنت ترغب في تحقيق INNER JOIN (:includes يعني LEFT OUTER JOIN, الذي هو أقل انتقائية أقل كفاءة من INNER JOIN.)

نصائح أخرى

وأو في القضبان 3 يمكنك استخدام أسلوب للقراءة فقط (استبدال "..." مع الظروف الخاصة بك):

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

وهذا قد تغيرت في الإفراج مؤخرا عن القضبان، ولكن الطريقة المناسبة لحل هذه المشكلة هو إضافة على : للقراءة فقط => كاذبة لخيارات العثور

وحدد ( '*') ويبدو لإصلاح هذا في القضبان 3،2:

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

وفقط للتحقق، وحذف حدد ( '*') لا تنتج سجل للقراءة فقط:

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

لا أستطيع أن أقول وأنا أفهم المنطق ولكن على الأقل أنها الحل السريع ونظيفة.

وبدلا من find_by_sql، يمكنك تحديد: اختيار على مكتشف وكل شيء سعيد مرة أخرى ...

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

لإلغاء تنشيطه ...

module DeactivateImplicitReadonly
  def custom_join_sql(*args)
    result = super
    @implicit_readonly = false
    result
  end
end
ActiveRecord::Relation.send :include, DeactivateImplicitReadonly
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top