Empêcher STI lors de l'héritage d'un modèle ActiveRecord
Sur Rails 3.2.6, j'ai une classe qui hérite de ActiveRecord:: Base:
class Section < ActiveRecord::Base
...
end
Quand j'hérite de cette classe, Rails supposera que je veux STI:
class AnotherSection < Section
..Rails assumes I have a type field, etc...
end
Je veux pouvoir hériter de la classe Section
et utiliser la sous-classe comme une sous-classe Ruby normale, sans la magie Rails STI.
Existe-t-il un moyen d'empêcher les STI lors du sous-classement d'un modèle ActiveRecord::Base
?
3 réponses
Vous pouvez y parvenir en désactivant le inheritance_column
pour le modèle, comme ceci:
class AnotherSection < Section
# disable STI
self.inheritance_column = :_type_disabled
end
La réponse acceptée fonctionnera certainement, mais le moyen recommandé (oserais-je dire "correct":) est de définir abstract_class
:
class Section < ActiveRecord::Base
self.abstract_class = true
end
La seule stratégie entièrement prise en charge pour stocker l'héritage sur ActiveRecord est STI. Vous pouvez, cependant, simuler l'héritage de table de classe concrète à vos propres risques. L'héritage de table de classe concrète avec une superclasse abstraite fonctionne bien, comme indiqué par smathy.
Mais ... Si ce que vous voulez est de faire AnotherSection juste une classe ordinaire (qui ne sera pas conservée dans la base de données), vous pouvez désactiver la colonne discriminateur (comme suggéré par Veraticus). Cependant, si vous enregistrez le AnotherSection il sera conservé dans la même table que la Section, et vous ne pourrez pas les distinguer. De plus, si vous utilisez AnotherSection pour trouver une Section , elle retournera une AnotherSection , brisant l'instanciation d'origine:
#create a Section and saves it
sect = Section.create()
sect.save()
#retrieve the Section as a AnotherSection, breaking polymorphism...
sect = AnotherSection.find(sect.id)
# another section is more than a section, it is inconsistent.
Si AnotherSection n'est pas destiné à être persistant, le chemin le plus sûr pour remplacer les opérations de persistance, telles que save () et find ():
class AnotherSection < Section
# disable STI, as pointed by Veraticus
self.inheritance_column = :_type_disabled
# disable save and finding
def save(*args)
#exception? do nothing?
end
def find(*args)
#exception? do nothing?
end
def find_by(*args)
#exception? do nothing?
end
# this does not stops here! there is first, last, and even a forty_two finder method! not to mention associations...
end
En un mot, vous pouvez le faire, mais vous SHOULDNT. Le risque est élevé. Vous devriez envisager une autre option, comme l'utilisation de MIXIN au lieu de l'héritage.