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?

26
demandé sur Mike 2012-07-26 23:02:54

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
32
répondu Veraticus 2012-07-26 19:10:39

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
11
répondu smathy 2015-07-13 23:03:07

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.

1
répondu atorres 2017-01-21 17:25:38