206 votes

Ce qui est à l’origine cette erreur ActiveRecord::ReadOnlyRecord ?

Ce qui suit cette question avant, ce qui a été répondu. J'ai en fait découvert que je pouvais supprimer une jointure à partir de cette requête, de sorte que maintenant le travail de la requête est

start_cards = DeckCard.find :all, :joins => [:card], :conditions => ["deck_cards.deck_id = ? and cards.start_card = ?", @game.deck.id, true]

Cela semble fonctionner. Cependant, lorsque j'essaie de déplacer ces DeckCards dans une autre association, j'ai le ActiveRecord::ReadOnlyRecord erreur.

Voici le code

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

et les Modèles (tableau sont les joueurs de cartes sur la table)

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

Je suis en train de faire une action similaire juste après ce code, l'ajout d' DeckCards de la main de joueurs, et que le code fonctionne bien. Je me suis demandé si j'avais besoin d' belongs_to :tableau dans le DeckCard Modèle, mais il fonctionne très bien pour l'ajouter à la main du joueur. J'ai un tableau_id et hand_id colonnes dans la DeckCard table.

J'ai regardé ReadOnlyRecord dans les rails de l'api, et il ne parle pas beaucoup au-delà de la description.

286voto

vladr Points 34562

À partir de la ActiveRecord CHANGELOG(v1.12.0, 16 octobre 2005):

Introduire les enregistrements en lecture seule. Si vous appelez de l'objet.readonly! puis il s' marque de l'objet en lecture seule et les élever ReadOnlyRecord si vous appelez objet.enregistrer. objet.readonly? les rapports si l'objet est en lecture seule. En passant :readonly => true pour tout méthode de recherche marquera retourné les dossiers en lecture seule. L' :joint option implique :readonly, donc si vous utilisez cette option, l'enregistrement de la même enregistrement va échouer. Utilisation find_by_sql pour contourner.

À l'aide de find_by_sql n'est pas vraiment une alternative de retour brut de ligne/colonne de données, pas ActiveRecords. Vous avez deux options:

  1. La Force de la variable d'instance, @readonly de la valeur faux dans le dossier (hack)
  2. Utiliser :include => :card au lieu de :join => :card

Sep 2010 mise à JOUR

La plupart des ci-dessus n'est plus vrai. Ainsi, dans les Rails 2.3.4 et 3.0.0:

  • à l'aide de Record.find_by_sql est une option viable
  • :readonly => true est automatiquement déduit seulement si :joins a été spécifié sans explicite :select ni explicite (ou le finder-champ d'application-héréditaire) :readonly option (voir la mise en œuvre de l' set_readonly_option! en active_record/base.rb pour les Rails 2.3.4, ou la mise en œuvre de l' to_a en active_record/relation.rb et de la custom_join_sql en active_record/relation/query_methods.rb pour les Rails 3.0.0)
  • toutefois, :readonly => true est toujours automatiquement déduit en has_and_belongs_to_many si la table de jointure a plus de deux clés étrangères colonnes et :joins a été spécifié sans explicite :select (c'est à dire fourni par l'utilisateur :readonly valeurs sont ignorées -- voir finding_with_ambiguous_select? en active_record/associations/has_and_belongs_to_many_association.rb.)
  • en conclusion, à moins de traiter avec une table de jointure et d' has_and_belongs_to_many, alors @aaronrustad's réponse s'applique très bien dans les Rails 2.3.4 et 3.0.0.
  • ne pas utiliser :includes , si vous voulez obtenir un INNER JOIN (:includes implique une LEFT OUTER JOIN, ce qui est moins sélectives et moins efficace que l' INNER JOIN.)

172voto

balexand Points 3691

Ou dans Rails 3 vous pouvez utiliser la méthode readonly (remplacez "..." par vos conditions):

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

45voto

Aaron Rustad Points 1417

Cela a peut-être changé dans la version récente de Rails, mais la façon appropriée de résoudre ce problème est d'ajouter : readonly => false aux options de recherche.

16voto

bronson Points 343

select ('*') semble corriger cela dans Rails 3.2:

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

Juste pour vérifier, omettre select ('*') produit un enregistrement en lecture seule:

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

Je ne peux pas dire que je comprends la raison, mais au moins c'est une solution de contournement rapide et propre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X