2017-10-14 2 views
0

Nous avons une application rails qui utilise 2 modèles: Image et Vidéo. Ils appartiennent tous deux à une entité de collection. Ce qui se passe est que si nous voulons interroger ou utiliser les deux types d'une manière unifiée - nous ne pouvons pas. Donc, si nous voulons aller chercher les 15 derniers, nous interrogeons deux fois, puis nous trions puis nous reprenons les 15. Si nous voulons trouver() un certain identifiant, nous devons toujours obtenir quel type il est - vidéo ou image ...Conception d'une classe polymorphe

Nous réfléchissions donc à la façon de résoudre ce problème. Détient un modèle Asset qui pointe vers l'un ou l'autre? Sera-t-il capable d'être chargé?

Dans ma vision, il doit s'agir d'Asset.find (_id) et j'obtiendrai Image ou Vidéo agnostiquement.

Quelle est la manière la plus simple ou la plus correcte de résoudre cela dans Rails?

Merci!

+0

Je pense que «enum» dans les rails est ce que vous cherchez. http://api.rubyonrails.org/v5.1/classes/ActiveRecord/Enum.html. J'espère que cette aide. – thanhnha1103

+0

Il n'y a pas de façon correcte de résoudre ce problème car c'est un exemple de [Différence d'impédance relationnelle d'objet] (https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch). La façon la plus courante de résoudre ce problème consiste à utiliser une table unique ou un héritage de tables multiples. – max

+0

L'utilisation de STI tel que décrit par Tamer vous permettra de faire MediaItem.find (id) et d'obtenir un modèle vidéo ou image en fonction du résultat – s1mpl3

Répondre

1

Vous pouvez utiliser Single Table Inheritance pour atteindre cet objectif.

Disons que vous avez un modèle appelé Media:

rails g model media_item type:string <other attributes here> 

Ensuite, vous héritez de lui deux modèles: Video et Image, comme ceci:

rails g model video --parent=MediaItem 
rails g model image --parent=MediaItem 

maintenant dans vos modèles:

class MediaItem < ApplicationRecord 
    belongs_to :collection 
end 

class Collection < ApplicationRecord 
    has_many :media_items 
end 

Cette approche vient avec som e inconvénients cependant. Par exemple, les sous-classes peuvent avoir de nombreux attributs différents, et vous pourriez avoir trop d'attributs qui sont utilisés dans une sous-classe mais pas dans l'autre, et vice versa.

Il existe certaines solutions de contournement pour cela, comme avoir un champ properties qui est semblable à un hachage et contient des attributs spécifiques à la sous-classe. Mais cela peut aussi devenir problématique si vous avez besoin d'indexer sur une propriété spécifique et que votre base de données ne supporte pas ces index. Ou vous pouvez simplement créer une table d'attributs séparée pour chaque sous-classe avec une relation 1-à-1, une méthode connue sous le nom d'héritage à tables multiples, mais qui présente également ses inconvénients. Tout dépend de votre cas d'utilisation spécifique.

+2

"Ou vous pouvez simplement créer une table d'attributs séparée pour chaque sous-classe avec une relation 1-à-1 " - C'est ce qu'on appelle communément l'héritage de plusieurs tables. – max

+0

@max Merci beaucoup, en fait, je ne savais pas qu'il a un nom lol. Mettra à jour la réponse en conséquence. –

+0

Je cherche à utiliser les modèles que j'ai maintenant. Ce que vous suggérez, c'est que je devrais convertir tous mes modèles et mon application en MediaItem. – Himberjack