Je construis un système qui a des enregistrements dans des tables qui sont des enregistrements de modèles, qui sont visibles par tous les comptes et peuvent être copiés ultérieurement pour créer des enregistrements en direct pour un compte individuel. Le motif de cette décision de conception est que les enregistrements de modèle et les enregistrements en cours partagent 95% et plus du même code, donc je ne voulais pas créer de table distincte pour suivre principalement les mêmes champs.Rails: plusieurs modèles fonctionnant sur la même table
Par exemple, j'ai une table workflows
:
- id: entier
- account_id: entier Nom
- : string (obligatoire)
- is_a_template: Boolean (default: false)
- is_in_template_library: booléen (par défaut: false)
Dans cette table, j'ai des enregistrements qui sont des modèles. Quand je vais créer un nouvel enregistrement en direct, je peux utiliser un enregistrement de modèle:
# workflows_controller.rb (pseudo-code, not fully tested)
def create
@workflow_template = Workflow.where(is_a_template: true).find_by(id: params[:workflow_template_id])
@workflow = current_account.workflows.new(workflow_params.merge(@workflow_template.dup))
if @workflow.save
...
else
...
end
end
Comme je construis plus de fonctionnalités, je trouve que j'ai vraiment besoin de 2 différents modèles qui fonctionnent différemment sur la table. Il y a plusieurs autres différences, mais celles qui sont énumérées ci-dessous suffisent pour montrer les différences:
class Workflow < ApplicationRecord
default_scope -> { where(is_a_template: false) }
belongs_to :account
validates :account, presence: true
validates :name, presence: true
end
class WorkflowTemplate < ApplicationRecord
default_scope -> { where(is_a_template: true) }
validates :name, presence: true
end
class WorkflowLibraryTemplate < ApplicationRecord
default_scope -> { where(is_a_template: true, is_in_template_library: true) }
validates :name, presence: true
end
Comme vous pouvez le voir, la table workflows
dispose de 3 différents « types » d'enregistrements:
- « live » les flux de travail qui appartiennent à un flux de travail de modèle compte
- qui appartiennent également à un compte et sont copiés pour créer des flux de travail « live »
- flux de travail de la bibliothèque de modèles qui ne font pas partie à un compte et peut être consulté par tout compte, afin qu'ils puissent les copier dans leur propre liste de modèles
Question
Ce que je suis en train de comprendre, à quel moment est-ce que je romps cette table unique en plusieurs tables, par rapport en gardant la même table et ayant plusieurs modèles, ou quelle est la solution à un problème comme celui-ci? La partie frustrante est qu'il y a 5 autres tables qui sont des associations "enfants" de la table workflows
. Donc si je décide que j'ai besoin de tables séparées pour chacune, je finirais par passer de 6 tables à quelque chose comme 18, et chaque fois que j'ajoute un champ, je dois le faire pour les 3 "versions" de la table.
Ainsi, je suis très réticent à descendre la route des tables multiples.
Si je garde une seule table et plusieurs modèles, je me retrouve avec une version différente des données dans la table, ce qui n'est pas la fin du monde. J'interagis seulement avec les données à travers mon application (ou une future API que je contrôle).
Une autre solution à laquelle je pense consiste à ajouter un champ role:string
à la table, qui fonctionne très bien comme le champ type
dans Rails.Je ne voulais pas utiliser STI, cependant, parce qu'il y a trop d'exigences dans Rails avec lesquelles je ne veux pas entrer en conflit.
Ce que je suis envisioning est:
class Workflow < ApplicationRecord
scope :templates, -> { where(role: "template") }
scope :library_templates, -> { where(role: "library_template") }
validates :account, presence: true, if: :account_required?
validates :name, presence: true
# If record.role matches one of these, account is required
def account_required
["live", "template"].include?(role.to_s.downcase)
end
end
Cela semble répondre à plusieurs des questions, me maintient avec 1 table et 1 modèle, mais commence à avoir une logique conditionnelle dans le modèle, ce qui semble être un mauvaise idée à moi aussi.
Existe-t-il une manière plus simple d'implémenter un système de modèle dans une table?
Avez-vous des difficultés particulières ou attendez-vous à rencontrer votre approche actuelle? – EJ2015
Ce que j'ai en production en ce moment, c'est un tas de logique conditionnelle qui est assez moche. Si je vais avec une approche STI, je vais devoir créer plusieurs fichiers de modèles différents qui implémentent la logique pour chacun séparément. Je pense que c'est plus facile à maintenir que plusieurs tables, cependant. Le gros problème avec STI est que je devrai avoir des fichiers modèles séparés pour toutes les associations, ce qui ajouterait 10+ fichiers de modèles. –