ruby-on-rails rails - ¿Qué está causando este error ActiveRecord::ReadOnlyRecord?




join table (6)

Para desactivarlo ...

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

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.


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.


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.


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:

  1. Forzar la variable de instancia @readonly a falso en el registro (hackear)
  2. 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 de set_readonly_option! en active_record/base.rb para Rails 2.3. 4, o la implementación de to_a en active_record/relation.rb y de custom_join_sql en active_record/relation/query_methods.rb para Rails 3.0.0)
  • sin embargo has_and_belongs_to_many :readonly => true siempre se deduce automáticamente en has_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 de 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 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 una INNER JOIN ( :includes implica una LEFT OUTER JOIN , que es menos selectiva y menos eficiente que la INNER JOIN ).

Esto me sucedió justo después de que reinstalé rbenv . Aparentemente tenía un archivo .ruby-version en mi directorio de inicio, especificando una versión que ya no existía. Una vez que borré el archivo, todo funcionó.





ruby-on-rails ruby activerecord join associations