2 votes

Est-ce que l'héritage sur une seule table est la bonne solution pour mon problème Rails?

Salutations à tous,

Je travaille sur une application en Ruby on Rails où nous avons besoin de suivre un tas de services externes pour chaque utilisateur (par exemple, Facebook, MySpace, Google, SalesForce, Twitter, WordPress, etc.) que l'application accèdera au nom de l'utilisateur. Pour certains services, nous devrons stocker un nom d'utilisateur et un mot de passe (crypté), pour d'autres nous devrons enregistrer des données OAuth, pour d'autres encore des données OAuth2, et ainsi de suite. A mesure que l'application se développe, nous devrons prendre en charge encore plus de types de comptes, chacun avec son propre ensemble de données d'authentification.

Chaque utilisateur peut créer des publications au sein de l'application, et nous prendrons ces publications et les enverrons aux services externes pour qu'elles soient publiées pour l'utilisateur. Nous suivrons ensuite la réponse à la publication (retweets sur Twitter, likes/shares sur Facebook, et ainsi de suite).

Donc :

class User < ActiveRecord::Base
  has_many :services
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :publishes
end

class Publish < ActiveRecord::Base
  has_one :service
  belongs_to :post
end

class Service < ActiveRecord::Base
  belongs_to :user
  belongs_to :publish
end

Je réfléchis à utiliser l'héritage sur une seule table pour mes types de Service (par exemple, WordpressService, FacebookService, TwitterService, et simplement sérialiser un simple hash pour sauvegarder les données d'authentification) et utiliser un schéma traditionnel, normalisé où chaque type de service a son propre modèle et sa propre table. J'aimerais pouvoir itérer facilement sur tous les Services associés à un utilisateur, et un Publish doit pouvoir être associé à n'importe quel type de Service (un Publish pourrait être envoyé à WordPress, Facebook, ou Twitter, par exemple).

Puis-je atteindre ce type de relation de modèle en utilisant une approche normalisée traditionnelle ? Ou est-ce exactement ce que l'héritage sur une seule table était censé résoudre ?

Merci.

2voto

Abe Points 146

Vous voudrez peut-être consulter le plugin omniauth qui est assez facile à configurer et gère le stockage des informations d'authentification pour un certain nombre de services dès le départ. Il y a quelques railscasts qui montrent comment le configurer. Sinon, vous pourriez voir comment ils suggèrent de stocker les choses.

2voto

Pedro Morte Rolo Points 5171

Comme alternative au STI, vous pourriez utiliser des associations polymorphes :

class AccountAuth < AR::Base
  belongs_to :account
  belongs_to :authentication, :polymorphic => true
end
# account_id          :integer
# authentication_id   :integer
# authentication_type :string

module Auth
  #logique commune
end

class FacebookAuth < AR::Base
  include Auth
  has_one :account_auth,:as=>:authentication
  has_one :account, :through => :account_auth
end

class Account < AR::Base
  has_many :account_auths
  has_many :authentications, :through => :account_auths
end

Ceci et cela peuvent vous aider.

0voto

Stephanie Page Points 2997

Combien de millions d'utilisateurs allez-vous stocker, à quelle fréquence interrogerez-vous la table? Je dirais en général que votre conception physique souffrirait de ce type de stockage, mais le matériel compensera ces lacunes de conception pour un grand nombre d'applications. Si vous n'opérez pas sur des données à grande échelle ou des transactions à haut volume, tout ce que vous créez sera suffisant.

0voto

Brandon Tilley Points 49142

Bien que je ne sois toujours pas sûr que ce soit la façon "correcte" de résoudre ce problème, j'ai décidé d'utiliser l'héritage sur une seule table afin de pouvoir facilement obtenir une liste de tous les services qu'un autre modèle has_many (puisque chaque sous-classe de Service est également un Service, je peux appeler model_instance.services pour les obtenir tous).

Pour résoudre le problème de la duplication de code, j'ai créé un module à utiliser dans n'importe quel modèle qui devrait has_many :services ainsi que chaque type de service :

module HasServices
  extend ActiveSupport::Concern
  included do
    has_many :services
    has_many :facebook_services
    has_many :twitter_services
    has_many :wordpress_services
  end

Service est également conscient de ses sous-classes, de sorte que les menus, etc. peuvent facilement être créés :

class Service < ActiveRecord::Base

  @child_classes = []

  ...

  protected

    def self.inherited(child)
      @child_classes << child
      super
    end

    def self.child_classes
      @child_classes
    end
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X