through rails left inner has_many has_and_belongs_to_many example active ruby-on-rails ruby activerecord join associations

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:

  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 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.