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
@readonly
a falso en el registro (hackear) - Use
:include => :card
lugar 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_sql
es una opción viable -
:readonly => true
se infiere automáticamente solo si:joins
se especificaron sin un explícito:select
ni una opción explícita (o de buscador heredado):readonly
(vea la implementación deset_readonly_option!
enactive_record/base.rb
para Rails 2.3. 4, o la implementación deto_a
enactive_record/relation.rb
y decustom_join_sql
enactive_record/relation/query_methods.rb
para Rails 3.0.0) - sin embargo
has_and_belongs_to_many
:readonly => true
siempre se deduce automáticamente enhas_and_belongs_to_many
si la tabla de unión tiene más de dos columnas de clave externa y:joins
se especificó una:joins
sin un explícito:select
(es decir, los valores de:readonly
se 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@aaronrustad
aplica bien en Rails 2.3.4 y 3.0.0. - no utilice
:includes
si desea obtener unaINNER JOIN
(:includes
implica 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.