Aquí podría ser tu PUBLICIDAD


¿Qué está causando este error ActiveRecord :: ReadOnlyRecord?

votos
198

Esto sigue a esta pregunta anterior, que fue respondida. De hecho, descubrí que podía eliminar una combinación de esa consulta, por lo que ahora la consulta de trabajo es

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

Esto parece funcionar. Sin embargo, cuando intento mover estos DeckCards a otra asociación, obtengo el error ActiveRecord :: ReadOnlyRecord.

Aquí está el código

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

y los Modelos relevantes (tableau son las cartas de los jugadores sobre la mesa)

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

Estoy haciendo una acción similar justo después de este código, agregando DeckCardsa la mano de los jugadores, y ese código funciona bien. Me pregunté si lo necesitaba belongs_to :tableauen el Modelo DeckCard, pero funciona bien para agregarlo a la mano del jugador. Tengo una tableau_idy hand_idcolumnas en la tabla DeckCard.

Busqué ReadOnlyRecord en la API apéndices, y no dice mucho más allá de la descripción.

Publicado el 12/03/2009 a las 16:28
fuente por usuario user26270
En otros idiomas...        العربية       

6 respuestas

votos
275

Desde ActiveRecord CHANGELOG(v1.12.0, 16 de octubre de 2005) :

Introduzca registros de solo lectura. Si llama a object.readonly! luego marcará el objeto como de solo lectura y elevará ReadOnlyRecord si llama a object.save. object.readonly? informa si el objeto es de solo lectura. Al pasar: readonly => true a cualquier método de búsqueda marcará los registros devueltos como de solo lectura. La opción: join ahora implica: solo lectura, por lo que si usa esta opción, el guardar el mismo registro ahora fallará. Usa find_by_sql para evitarlo.

Usar find_by_sqlno es realmente una alternativa, ya que devuelve datos de fila / columna sin procesar, no ActiveRecords. Tienes dos opciones:

  1. Forzar la variable de instancia @readonlya falso en el registro (hackear)
  2. Use en :include => :cardlugar de:join => :card

Actualización de septiembre de 2010

La mayoría de las anteriores ya no son ciertas. Por lo tanto, en Rails 2.3.4 y 3.0.0:

  • usar Record.find_by_sql es una opción viable
  • :readonly => truese deduce automáticamente solo si :joinsse especificó sin una opción explícita :select ni explícita (o finder-scope-inherited) :readonly(ver la implementación de set_readonly_option!in active_record/base.rbpara Rails 2.3.4, o la implementación de to_ain active_record/relation.rband of custom_join_sqlin active_record/relation/query_methods.rbpara Rails 3.0.0)
  • sin embargo, :readonly => truesiempre se deduce automáticamente en has_and_belongs_to_manysi la tabla de unión tiene más que las dos columnas de claves externas y :joinsse especificó sin una explícita :select(es decir, los :readonlyvalores suministrados por el usuario se ignoran, ver finding_with_ambiguous_select?en active_record/associations/has_and_belongs_to_many_association.rb).
  • en conclusión, a menos que se trate de una tabla de combinación especial y has_and_belongs_to_many, entonces @aaronrustad, la respuesta se aplica perfectamente en Rails 2.3.4 y 3.0.0.
  • no no usar :includessi quiere lograr un INNER JOIN( :includesimplica una LEFT OUTER JOIN, que es menos selectiva y menos eficientes que INNER JOIN.)
Respondida el 12/03/2009 a las 07:15
fuente por usuario vladr


Aquí podría ser tu PUBLICIDAD


votos
168

O en Rails 3 se puede utilizar el método de sólo lectura (sustituir "..." con sus condiciones):

( Deck.joins(:card) & Card.where('...') ).readonly(false)
Respondida el 10/08/2010 a las 12:50
fuente por usuario balexand

votos
43

Esto podría haber cambiado en la versión reciente de Rails, pero la forma adecuada de resolver este problema es agregar : readonly => false a las opciones de búsqueda.

Respondida el 07/06/2009 a las 01:32
fuente por usuario Aaron Rustad

votos
15

seleccionar ( '*') parece solucionar este problema en Rails 3.2:

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

Sólo para verificar, omitiendo seleccione ( '*') no producirá un registro de sólo lectura:

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

No se puede decir que entiendo la razón, pero al menos es una solución rápida y limpia.

Respondida el 01/03/2013 a las 11:17
fuente por usuario bronson

votos
5

En lugar de find_by_sql, puede especificar un: seleccionar en el buscador y todo está feliz otra vez ...

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

Respondida el 27/03/2009 a las 01:32
fuente por usuario Harold Gimenez

votos
3

Para desactivarlo ...

module DeactivateImplicitReadonly
  def custom_join_sql(*args)
    result = super
    @implicit_readonly = false
    result
  end
end
ActiveRecord::Relation.send :include, DeactivateImplicitReadonly
Respondida el 10/08/2012 a las 11:31
fuente por usuario grosser