Pregunta

Esto sigue 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 estas DeckCards a otra asociación, aparece 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 (el 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 del jugador, y ese código funciona bien. Me preguntaba si necesitaba belong_to: tableau en el modelo DeckCard, pero funciona bien para agregar a la mano del jugador. Tengo una columna tableau_id y hand_id en la tabla DeckCard.

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

¿Fue útil?

Solución

Rails 2.3.3 y versiones inferiores

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

  

Introducir registros de solo lectura. Si llamas a object.readonly! entonces lo hará   marcar el objeto como solo lectura y elevar   ReadOnlyRecord si llamas   object.save. object.readonly? informes   si el objeto es de solo lectura.   Pasando: readonly = > fiel a cualquier   el método del buscador marcará devuelto   registros como de solo lectura. El: se une   La opción ahora implica: solo lectura, así que si   usa esta opción, guardando la misma   el registro ahora fallará. Use find_by_sql   para evitarlo.

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

  1. Forzar la variable de instancia @readonly a false en el registro (piratear)
  2. Use : include = > : tarjeta en lugar de : join = > : tarjeta

Rails 2.3.4 y superior

La mayoría de lo anterior ya no es cierto, después del 10 de septiembre de 2012:

  • usando Record.find_by_sql es una opción viable
  • : readonly = > verdadero se infiere automáticamente solo si : une se especificó sin un explícito: seleccione ni una opción : readonly explícita (o hereditaria-alcance-heredada) (vea la implementación de set_readonly_option! en active_record / base.rb para Rails 2.3.4, o la implementación de to_a en active_record / relacion.rb y de custom_join_sql en active_record / relacion /query_methods.rb para Rails 3.0.0)
  • sin embargo, : readonly = > verdadero siempre se infiere automáticamente en has_and_belongs_to_many si la tabla de unión tiene más de las dos columnas de claves foráneas y se especificó : une sin un explícito: seleccione (es decir, los valores : readonly proporcionados por el usuario se ignoran; consulte finding_with_ambiguous_select? en active_record / asociaciones / 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 se aplica perfectamente en Rails 2.3.4 y 3.0.0.
  • no no use : incluye si desea lograr una UNIÓN INTERNA (: incluye implica un < code> LEFT OUTER JOIN , que es menos selectivo y menos eficiente que INNER JOIN .)

Otros consejos

O en Rails 3 puede usar el método de solo lectura (reemplace " ... " con sus condiciones):

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

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

select ('*') parece corregir esto en Rails 3.2:

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

Solo para verificar, omitir select ('*') produce un registro de solo lectura:

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

No puedo decir que entiendo la lógica, pero al menos es una solución rápida y limpia.

En lugar de find_by_sql, puede especificar a: select en el buscador y todo vuelve a ser feliz ...

start_cards = DeckCard.find: all,   : select = > 'deck_cards. *',   : se une = > [:tarjeta],   : condiciones = > [" deck_cards.deck_id =? y cards.start_card =? " ;, @ game.deck.id, verdadero]

Para desactivarlo ...

module DeactivateImplicitReadonly
  def custom_join_sql(*args)
    result = super
    @implicit_readonly = false
    result
  end
end
ActiveRecord::Relation.send :include, DeactivateImplicitReadonly
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top