J'ai actuellement la structure de modèle et les relations suivantes
class Fleet < ApplicationRecord
# properties id, created_at, updated_at
# A fleet should only consists of the same type, either a fleet or cars or a fleet of trains. Never both
has_many :cars
has_many :trains
end
class Car < ApplicationRecord
# properties id, created_at, updated_at, number_of_gears, is_sports_car
belongs_to :fleet
end
class Train < ApplicationRecord
# properties id, created_at, updated_at, number_of_wagons, people_capacity, has_first_calass_section
belongs_to :fleet
end
Le problème que j'ai est qu'une flotte ne devrait être constituée que du même type, soit une flotte de voitures, soit une flotte de trains. Jamais les deux.
Avec les relations actuelles sur la flotte, il semble sujet aux erreurs d'avoir à la fois des associations has_many (ou plus venant comme des avions) en termes d'intégrité et de facilité d'utilisation lors de l'appel à @ flotte._cars -ou-trains , je devrais savoir ce que je peux appeler.
STI n'est pas une option car les propriétés sont très différentes sur une voiture et un train. Il y a beaucoup plus de propriétés, par souci de simplicité, je les ai raccourcies dans cet exemple.
Quelle est la bonne façon de procéder dans Rails?
3 Réponses :
J'utiliserais deux modèles différents: CarsFleet et TrainsFleet. Les deux peuvent étendre un modèle de flotte mais définir une autre association has_many .
Alors "Car" appartiendrait à un cars_fleet et "Train" appartiendrait à un trains_fleet.
C'est à cela que servent les relations polymorphes .
A Flotte peut avoir de nombreux véhicules , et un véhicule peut être soit une voiture soit un train code > et, surtout, jamais les deux.
class Fleet < ApplicationRecord belongs_to :vehicles, polymorphic: true # notice the belongs_to, it's the only way polymorphism works from memory end class Car < ApplicationRecord has_one :fleet, as: :vehicle end class Train < ApplicationRecord has_one :fleet, as: :vehicle end
De cette façon, vous pouvez appeler flotte.vehicles sans vous soucier de la classe.
Ce code n'a pas été testé, mais il devrait vous permettre de franchir la ligne, et c'est le moyen le plus efficace de résoudre votre problème.
Une flotte peut avoir plusieurs voitures ou plusieurs trains. Je ne vois pas comment cela fonctionnerait avec cet exemple
Vous pouvez ajouter une validation de modèle pour vérifier ceci:
validates_associated :fleet
Ce qui précède devrait empêcher les flottes d'être enregistrées lorsqu'elles ont à la fois des voitures et des trains présents. Cependant, vous pouvez toujours créer des voitures et des trains séparément et les lier à une flotte.
# assuming a valid fleet exist fleet = Fleet.create # should save # you can still create both cars and trains fleet.cars.create # should save fleet.trains.create # should save # however when you retry to save the fleet it fails on the validation fleet.save # should fail
Dans le scénario ci-dessus, nous aimerions également déclencher les validations de flotte lors de la création d'une voiture ou d'un train . Pour ce faire, ajoutez un validates_associated : p>
class Fleet < ApplicationRecord
has_many :cars
has_many :trains
validates :cars, absence: true, if: -> { trains.any? }
validates :trains, absence: true, if: -> { cars.any? }
end
Dans les modèles Car et Train . Cela devrait maintenant empêcher la voiture et le train ci-dessus d'être sauvegardés.
Notez que cette réponse n'empêche rien de SQL et les enregistrements sont toujours techniquement autorisés dans la base de données. Si vous ne le souhaitez pas, vous devez créer un déclencheur qui s'exécute AFTER INSERT et AFTER UPDATE . Comme il s'agit de SQL, je suggérerais de poser une nouvelle question si vous rencontrez des problèmes avec la création de déclencheurs. Mentionnez la base de données utilisée car la syntaxe du déclencheur n'est pas la même pour tous les types de bases de données (MySQL, SQL Server, ...).
Quel est le point commun entre les deux types de flottes?
Pas beaucoup, juste 2-3 champs d'environ 10-13 champs au total
S'ils ont si peu de choses en commun, doivent-ils être dans le même modèle?
Non, c'est pourquoi j'ai un modèle de voiture et de train séparé
Oh.
CarFleetetTrainFleetensuite.