这遵循了前面的问题,这个问题已经得到了回答。实际上我发现我可以从那个查询中删除一个连接,所以现在工作的查询是

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

这似乎奏效了。然而,当我试图将这些deck移动到另一个关联时,我得到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

和相关的模型(tableau是桌子上的玩家卡)

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表。

我在rails api中查找了ReadOnlyRecord,除了描述之外,它并没有提供太多信息。


当前回答

而不是find_by_sql,你可以在查找器上指定一个:select,一切都很愉快…

start_cards = DeckCard。发现:, :select => 'deck_cards.*', :joins => [:card], :conditions => ["deck_cards.deck_id = ? "和卡片。Start_card = ?", @game.deck.id, true]

其他回答

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

我不能说我理解其中的原理,但至少这是一个快速而干净的解决方法。

要解除它…

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

或者在Rails 3中,你可以使用readonly方法(用你的条件替换"…"):

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

这可能在最近的Rails版本中有所改变,但解决这个问题的适当方法是在find选项中添加:readonly => false。

而不是find_by_sql,你可以在查找器上指定一个:select,一切都很愉快…

start_cards = DeckCard。发现:, :select => 'deck_cards.*', :joins => [:card], :conditions => ["deck_cards.deck_id = ? "和卡片。Start_card = ?", @game.deck.id, true]