![](/img/trans.png)
[英]ActiveRecord::ReadOnlyRecord: ActiveRecord::ReadOnlyRecord
[英]What is causing this ActiveRecord::ReadOnlyRecord error?
這是在這個先前的問題之后得到回答的。 我實際上發現我可以從該查詢中刪除一個連接,所以現在工作查詢是
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
添加到玩家手中,並且該代碼工作正常。 我想知道我是否需要在DeckCard模型中使用belongs_to :tableau
,但它適用於添加到玩家手中。 我在DeckCard表中有一個tableau_id
和hand_id
列。
我在rails api中查找了ReadOnlyRecord,並沒有超出描述范圍。
Rails 2.3.3及更低版本
來自ActiveRecord CHANGELOG
(2005年10月16日v1.12.0) :
引入只讀記錄。 如果你調用object.readonly! 然后它會將對象標記為只讀,如果調用object.save則引發ReadOnlyRecord。 object.readonly? 報告對象是否為只讀。 傳遞:readonly => true到任何finder方法都會將返回的記錄標記為只讀。 :join連接選項現在暗示:readonly,因此如果使用此選項,則保存相同的記錄現在將失敗。 使用find_by_sql來解決。
使用find_by_sql
並不是一種替代方法,因為它返回原始行/列數據,而不是ActiveRecords
。 您有兩種選擇:
@readonly
為false(hack) :include => :card
而不是:join => :card
Rails 2.3.4及以上版本
2012年9月10日之后,上述大多數情況不再適用:
Record.find_by_sql
是一個可行的選擇 :readonly => true
僅在:joins
情況下自動推斷:joins
在沒有顯式的情況下指定了:joins
:select
也沒有顯式(或finder-scope-inherited) :readonly
選項(請參閱active_record/base.rb
的set_readonly_option!
對Rails 2.3的實現。如圖4所示,或實施to_a
在active_record/relation.rb
和custom_join_sql
在active_record/relation/query_methods.rb
為Rails 3.0.0) :readonly => true
總是在has_and_belongs_to_many
自動推斷,並且:joins
指定了:joins
而沒有顯式:select
(即用戶提供的:readonly
值被忽略 - 請參閱finding_with_ambiguous_select?
在active_record/associations/has_and_belongs_to_many_association.rb
。) has_and_belongs_to_many
,否則@aaronrustad
的答案在Rails 2.3.4和3.0.0中應用得很好。 :includes
,如果你想達到一個INNER JOIN
( :includes
意味着LEFT OUTER JOIN
,這是選擇性較差,比效率較低的INNER JOIN
)。 或者在Rails 3中,您可以使用readonly方法(將“...”替換為您的條件):
( Deck.joins(:card) & Card.where('...') ).readonly(false)
這可能在最近發布的Rails中已經改變,但解決此問題的適當方法是在find選項中添加:readonly => false 。
select('*')似乎在Rails 3.2中解決了這個問題:
> Contact.select('*').joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly?
=> false
只是為了驗證,省略select('*')會產生一個只讀記錄:
> Contact.joins(:slugs).where('slugs.slug' => 'the-slug').first.readonly?
=> true
不能說我理解其基本原理,但至少它是一個快速而干凈的解決方法。
而不是find_by_sql,你可以在finder上指定一個:select,一切都很開心......
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 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.