ما هو الذي يسبب هذا ActiveRecord::ReadOnlyRecord الخطأ ؟
-
11-07-2019 - |
سؤال
هذا يلي هذا قبل السؤال الذي أجاب.أنا فعلا اكتشفت يمكنني إزالة الانضمام من أن الاستعلام حتى الآن العمل الاستعلام
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
.لديك خياران:
- القوة على سبيل المثال متغير
@readonly
إلى خطأ في سجل (هاك) - استخدام
: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