2
votes

Comment modéliser ces relations dans Rails

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?


5 commentaires

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. CarFleet et TrainFleet ensuite.


3 Réponses :


1
votes

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.


0 commentaires

1
votes

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.


1 commentaires

Une flotte peut avoir plusieurs voitures ou plusieurs trains. Je ne vois pas comment cela fonctionnerait avec cet exemple



0
votes

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, ...).


0 commentaires