ruby on rails - rails - ¿Qué está causando este error ActiveRecord:: ReadOnlyRecord?
rails join table (6)
Desde el CHANGELOG ActiveRecord (v1.12.0, 16 de octubre de 2005) :
Introducir registros de sólo lectura. Si llamas a object.readonly! luego marcará el objeto como de solo lectura y aumentará ReadOnlyRecord si llama a object.save. object.readonly? informa si el objeto es de solo lectura. Pasar: readonly => true a cualquier método de buscador marcará los registros devueltos como de solo lectura. La opción: se une ahora implica: solo lectura, por lo tanto, si usa esta opción, guardar el mismo registro ahora fallará. Utilice find_by_sql para evitar.
El uso de find_by_sql no es realmente una alternativa, ya que devuelve datos de fila / columna sin procesar, no ActiveRecords . Tienes dos opciones:
- Forzar la variable de instancia
@readonlya falso en el registro (hackear) - Use
:include => :cardlugar de:join => :card
Sep 2010 ACTUALIZACIÓN
La mayoría de los anteriores ya no es cierto. Así, en Rails 2.3.4 y 3.0.0:
-
Record.find_by_sqles una opción viable -
:readonly => truese infiere automáticamente solo si:joinsse especificaron sin un explícito:selectni una opción explícita (o de buscador heredado):readonly(vea la implementación deset_readonly_option!enactive_record/base.rbpara Rails 2.3. 4, o la implementación deto_aenactive_record/relation.rby decustom_join_sqlenactive_record/relation/query_methods.rbpara Rails 3.0.0) - sin embargo
has_and_belongs_to_many:readonly => truesiempre se deduce automáticamente enhas_and_belongs_to_manysi la tabla de unión tiene más de dos columnas de clave externa y:joinsse especificó una:joinssin un explícito:select(es decir, los valores de:readonlyse ignoran; consulte la página definding_with_ambiguous_select?enactive_record/associations/has_and_belongs_to_many_association.rb.) - En conclusión, a menos que se trate de una tabla de unión especial y
has_and_belongs_to_many, entonces la respuesta de@aaronrustadaplica bien en Rails 2.3.4 y 3.0.0. - no utilice
:includessi desea obtener unaINNER JOIN(:includesimplica unaLEFT OUTER JOIN, que es menos selectiva y menos eficiente que laINNER JOIN).
Esto sigue a this pregunta anterior, que fue respondida. Descubrí que podía eliminar una unió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 estas 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 (cuadro son las cartas de los jugadores en 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 DeckCards a la mano de los jugadores, y ese código funciona bien. Me pregunté si necesitaba belongs_to :tableau en el modelo de DeckCard, pero funciona bien para agregar a la mano del jugador. Tengo columnas tableau_id y hand_id en la tabla DeckCard.
Busqué ReadOnlyRecord en el api de los rieles, y no dice mucho más allá de la descripción.
En lugar de find_by_sql, puede especificar a: select en el buscador y todo volverá a ser feliz ...
start_cards = DeckCard.find :all, :select => ''deck_cards.*'', :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]
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.
O en Rails 3 puede usar el método de solo lectura (reemplace "..." con sus condiciones):
( Deck.joins(:card) & Card.where(''...'') ).readonly(false)
Para desactivarlo ...
module DeactivateImplicitReadonly
def custom_join_sql(*args)
result = super
@implicit_readonly = false
result
end
end
ActiveRecord::Relation.send :include, DeactivateImplicitReadonly
Select (''*'') parece arreglar esto en Rails 3.2:
> Contact.select(''*'').joins(:slugs).where(''slugs.slug'' => ''the-slug'').first.readonly?
=> false
Solo para verificar, omitiendo select (''*'') produce un registro de solo lectura:
> Contact.joins(:slugs).where(''slugs.slug'' => ''the-slug'').first.readonly?
=> true
No puedo decir que entiendo la razón, pero al menos es una solución rápida y limpia.