2008-11-28 10 views
2

Je suis en train de vérifier qu'un paramètre est une instance d'une classe spécifique dans Rails:Rails: appeler une classe de modèle dans une bibliothèque

def schedule(action, *args) 
    if arg.is_a? Aircraft 
    ... 
    end 
end 

Je fais cela dans une classe de bibliothèque (le fichier est dans lib/) et j'obtiens une erreur non initialisée constante Aircraft. Aircraft est une classe de modèle, avec un aircraft.rb fichier dans app/modèles. Puis-je utiliser des classes et des instances de modèle dans une bibliothèque? Comment?


contexte d'erreur:

L'erreur se produit dans les tests RSpec; le code fonctionne dans le navigateur. J'ai essayé de demander le modèle dans le fichier _spec.rb, pas de succès pour le moment.

Répondre

3

Cela vous donnera accès au modèle de l'avion:

require File.dirname(__FILE__) + "/../app/models/aircraft" 

[modifier]

Daniel apporte un bon point sur le contexte. Si vous utilisez une tâche de râteau assurez-vous que vous chargez l'environnement:

task :my_task => :environment do 
    # something happens... 
end 
4

Vous pouvez utiliser des classes de modèle dans les fichiers de bibliothèque Rails et que vous faites exactement de la façon correcte. Les rails devraient charger automatiquement l'avion de classe quand il est référé.

Nous avons donc besoin d'un peu plus de contexte pour comprendre pourquoi il échoue pour vous. Est-il possible que vous chargiez le fichier lib/fichier sans l'environnement Rails? Une façon de résoudre ce problème serait d'exiger explicitement le fichier modèle aircraft.rb. Cependant, vous trouverez que cette approche mène rapidement à la folie car elle va casser le chargeur automatique Rails de manière subtile et étonnante. Rails est beaucoup plus facile si vous travaillez avec le chargeur de classe Rails, pas contre.

Mise à jour

Donc, s'il est dans un test RSpec, peut-on voir le code que vous utilisez pour charger l'environnement dans le fichier de spécification? Il devrait ressembler à quelque chose comme ceci:

require File.dirname(__FILE__) + '/../spec_helper' 

et il doit être au début du fichier. Cela suppose à la fois que vous avez installé le plugin RSpec Rails (here) et que vous avez le fichier spec/spec_helper.rb par défaut du plugin RSpec. S'il n'y a pas un tel fichier, essayez d'exécuter:

ruby script/generate rspec 
+0

Ah, merci beaucoup! Tu m'as indiqué dans la bonne direction: ça marche parfaitement bien dans le navigateur. Je ne l'ai pas encore essayé parce que je fais du TDD: ça casse en RSpec. Je vais modifier la question. –

0

DEVONS essayé celui-ci: if arg.is_a? ::Aircraft?

1

La réponse de Daniel est correcte, mais considérez: pourquoi une classe de bibliothèque fait-elle référence à une classe de modèle? Le code de bibliothèque ne doit pas connaître les classes de modèles réelles, bien qu'il puisse connaître l'interface qu'elles fournissent.

Autre considération: pourquoi la méthode #schedule demande-t-elle la classe du modèle? Si une nouvelle classe de modèle, Spaceship voulait fonctionner avec #schedule, alors #schedule devrait changer pour fonctionner avec elle. Ce n'est pas nécessaire.

A la place, en quoi les objets Aircraft et les objets d'autres classes sont-ils traités par #schedule? Pouvez-vous extraire cette différence dans une méthode qui lui est propre? Ensuite, vous pouvez déplacer ces implémentations dans chacune des classes du modèle, et décider laquelle est utilisée par le polymorphisme, et non par le branchement.

Par exemple, ce qui était:

def schedule(action, vehicle) 
    if vehicle.is_an?(Aircraft) 
    possible_days = case action 
    when "travel" 
     ["Mon", "Wed", "Fri"] 
    when "repair" 
     ["Sat", "Sun"] 
    end 
    possible_days.rand 
    elsif vehicle.is_a?(Spaceship) 
    possible_days = case action 
    when "travel" 
     ["Sat", "Tue", "Thu"] 
    when "repair" 
     ["Sun", "Mon"] 
    end 
    possible_days.rand 
    end 
end 

deviendrait:

def schedule(action, vehicle) 
    vehicle.days_action_can_be_performed(action).rand 
end 


class Aircraft 
    def days_action_can_be_performed(action) 
    possible_days = case action 
    when "travel" 
     ["Mon", "Wed", "Fri"] 
    when "repair" 
     ["Sat", "Sun"] 
    end 
    possible_days 
    end 
end 

class Spaceship 
    def days_action_can_be_performed(action) 
    possible_days = case action 
    when "travel" 
     ["Sat", "Tue", "Thu"] 
    when "repair" 
     ["Sun", "Mon"] 
    end 
    possible_days 
    end 
end 

Quand une nouvelle classe est ajoutée, il a juste besoin de mettre en œuvre #days_action_can_be_performed, et il travaillera avec #schedule.