2009-11-12 15 views
0

J'ai quelques joueurs et les joueurs ont un état de commerce. Plutôt que d'écrire des codes durs comme "actif" et "inactif", puis de chercher des chaînes, je pensais que je serais intelligent et que je disposerais d'un modèle TradeState séparé pour qu'un joueur ait un trade_state_id (un joueur ne peut être qu'en un état de commerce à la fois). Maintenant, il serait pratique de pouvoir obtenir tous les joueurs actifs en utilisant des portées nommées, puis en disant "Player.active". Pour ce faire, je dois obtenir l'ID des enregistrements TradeState qui correspond « actif », donc je suis venu avec cela dans la classe du joueur:Rspec, ordre de chargement du modèle, les montages et le défi named_scope

named_scope :active, :conditions => {:trade_state_id => TradeState.active.first.id} 

Cela fonctionne comme un charme lorsqu'il est testé dans le script/console, mais ça ne marche pas quand je vais tester. J'utilise RSpec, mais je suppose que ce n'est pas pertinent. Quand je lance le test le plus trivial, je reçois l'erreur suivante:

« appelé id pour nul, ce qui serait par erreur de 4 »

Pour autant que je peux dire, le cadre d'essais chargement et l'analyse des modèles par ordre alphabétique. Le framework analyse l'appel named_scope dans le modèle Player et va consciencieusement rechercher l'identifiant du premier enregistrement TradeState actif. Cependant, ce modèle n'a pas encore été traité et n'est pas prêt, d'où l'erreur concernant l'obtention de l'ID de zéro. Au début, je pensais que c'était parce qu'il n'y avait pas d'enregistrements dans la table trade_states, donc je crée et enregistre les trade_states dont j'avais besoin dans le bloc before (: each), mais cela n'a pas fonctionné. Alors j'ai fait quelques montages et j'ai essayé de les charger, mais ça n'a pas marché.

Est-ce que cela semble plausible? Y a-t-il d'autres explications? Que diriez-vous de travailler autour? Je pourrais essayer de se moquer de l'objet TradeState et je vais essayer.

Merci beaucoup pour votre temps.

+0

Je dirais, "oui", il est plausible qu'il n'y a rien dans votre base de données, par conséquent, appeler "id" sur nil (retourné par TradeState.active.first) lancerait une erreur. Je ne peux pas dire pourquoi votre table est vide parce que vous dites seulement "ça n'a pas marché" sans code. –

Répondre

0

Ce morceau de code que vous avez mentionné est exécuté lorsque le joueur est "chargé". Donc, même si vous créez les données d'installation dans le bloc before (: each), ce modèle aurait pu être chargé avant cela. Pour résoudre le problème, vous pouvez essayer quelque chose comme:

named_scope :active, lambda { {:conditions => {:trade_state_id => TradeState.active.first.id} } } 

Cela garantit que le TradeState.active est appelé à chaque fois que vous appelez la named_scope.

Mais qu'est-ce que vous obtenez en appelant TradeState.active.first. Au lieu de cela, vous pouvez le faire de cette façon agréable

:conditions => {:trade_state_id => TradeState::ACTIVE} 

avec le code suivant sur votre modèle TradeState:

class TradeState < ActiveRecord::Base 
    def self.const_missing(sym) 
    const_set(sym, find_by_name(sym.to_s)) 
    end 
end 
+0

J'aime la solution pour utiliser la constante et la paramétrer dynamiquement. Cependant, lors de l'exécution des tests, le même problème est resté; En effet, bien qu'il y ait des enregistrements dans la table trade_states, l'instanciation du modèle Player avant que le modèle TradeState produise toujours une référence nulle. –

+0

Pouvez-vous poster votre code rspec, pour obtenir une image plus claire des wats en cours .. – Selva

0

Ceci est en fait un résultat potentiellement « attendu ».Si vous avez pas de joueurs actifs, puis

TradeState.active 

est vide, et donc

TradeState.active.first 

est nul,

et donc

TradeState.active.first.id 

appels Object::id sur un objet nul.

Vous pouvez essayer:

TradeState.active.empty? ? 0 : TradeState.active.first[:id] 

Dans tous les cas, assurez-vous d'inclure trade_states juste pour vous assurer qu'ils sont présents pour la jointure.

0

Malheureusement, bien que toutes ces suggestions étaient très bonnes, rien ne fonctionnait de manière fiable lors de l'exécution des cas de test. Au début, j'ai supprimé tout ce code, mais le code que j'avais à écrire était tellement moins attrayant que j'ai commencé à repenser le problème. Parce que nous recherchons beaucoup les joueurs par leur état commercial, avoir un index sur une colonne d'état de commerce numérique est une priorité claire. Cependant, il n'y a rien qui dise que l'état du commerce doit être un tableau, car il n'y a que quelques états commerciaux définis et il est peu probable qu'il y aura jamais beaucoup de volatilité dans les états commerciaux définis. Par conséquent, j'ai fait de TradeState une classe à part entière, ne dérivant plus d'ActiveRecord, et j'ai défini les constantes dont j'avais besoin.

Merci à tous pour vos idées et vos solutions.