2009-12-31 12 views
2

donc je configure des modèles et ils sont basés sur 2 classes de base abstraites (ou plutôt ils étaient des classes). Après avoir rencontré beaucoup de problèmes avec la manipulation de STI par Datamapper pour mon cas d'utilisation, qui semble être un bug ouvert sur leur page phare, j'ai plutôt décidé de faire des modules pour définir toutes les propriétés pour garder mes modèles DRY. Malheureusement, j'ai un problème de portée, et ce qui complique les choses, c'est que je dois utiliser deux niveaux d'héritage. Voici mon code:En utilisant des modules pour définir des propriétés avec Datamapper

module Part 
    def self.included(receiver) 
    receiver.class_eval do 
     include DataMapper::Resource 
     property :id,  Serial 
     #other junk 
    end 
    end 
end 

module HardDrive 
    def self.included(receiver) 
    receiver.class_eval do 
     include Part 
     property :kind,   Enum[:magnetic, :flash] 
     #buncha crap here 
    end 
    end 
end 

class Fujitsu 
    include HardDrive 
    property :rev, String 
end 

L'erreur que je reçois est:

uninitialized constant HardDrive::Enum (NameError) 
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:80:in `const_missing' 
from ./app/models/hard_drive.rb:6:in `included' 
from ./app/models/hard_drive.rb:4:in `class_eval' 
from ./app/models/hard_drive.rb:4:in `included' 
from ./app/models/hard_drives/fujitsu.rb:2:in `include' 
from ./app/models/hard_drives/fujitsu.rb:2 

Je suis un peu perdu. Quelqu'un sait-il comment je pourrais résoudre ceci ou mieux encore, une manière plus intelligente que je pourrais faire ceci?

Répondre

2

Il me semble que Enum est défini sous les modules DataMapper et la portée HardDrive ne le résout pas. (Vous voulez savoir pourquoi?)

Il suffit de mettre DataMapper :: Enum au lieu de Enum et cela devrait fonctionner. Dans une discussion plus générale, êtes-vous sûr que vous avez réellement besoin de ces abstractions? Un inconvénient que je vois dans votre code est que vous ne serez pas en mesure d'interroger votre base de données pour les pièces et les disques durs parce que la logique est stockée dans les modules ruby ​​au lieu de dans la base de données.

Mise à jour (après un commentaire de l'auteur)

La réponse générale est: oublier les IST. Alors que ORM est agréable à avoir, la meilleure partie d'entre eux est l'abstraction de backend SQL. Alors qu'ils vous donnent l'impression que vous pouvez avoir un modèle d'objet persisten, les abstractions souvent fuient et STI est un bon exemple. Je ne vais pas aller dans les détails ici mais vous pouvez trouver des ressources en ligne. Le mieux est que vous restiez assez proche des meilleures pratiques de modélisation SQL, comme les relations un, un, plusieurs et plusieurs.

Voici une version mise à jour. Je n'ai pas testé et les noms de méthode sont probablement faux, mais vous avez l'idée:

class Part 
    property :serial_number 
    has_one Manufacturer 
end 

class HardDisk 
    property :technology 
    property :platters 
    property :model 
    #... 
    is_one Part 
end 

class Manufacturer 
    property :name #Fujitsu, ... 
    property :website 
    #... 
    has_many HardDisk, [:trough=>Part] 
end 
+0

J'voudrais seulement d'utiliser une partie ou HardDrive pour moteurs de recherche, pour que je puisse faire Part.all puis rendre vues basé sur cela, mais ce n'est pas une grosse perte. J'ai essayé d'utiliser l'héritage, mais pour autant que je sache, je ne peux pas utiliser l'héritage ruby ​​et l'utiliser pour utiliser des tables différentes pour les sous-classes. J'ai d'abord conçu cela avec STI comme je l'ai dit mais il y a un bug connu dans DM sur leur page de phare qui empêche cela. Quelle stratégie utiliseriez-vous? – Technocrat