如何在Rails中为这些关系建模

时间:2019-08-18 22:16:12

标签: ruby-on-rails database

我目前具有以下模型结构和关系

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

我的问题是,一个车队只能由同一类型组成,无论是车队还是火车队。永远不要。

在当前与机队的关系方面,在调用@fleet._cars-or-trains时,在完整性和易用性方面,同时具有has_many关联(或更多类似Airplanes的关联)似乎很容易出错,我必须知道自己能做什么打电话。

STI不是选项,因为汽车和火车的属性非常不同。为了简化起见,在本示例中我将它们缩短了,因此还有更多的属性。

Rails执行此操作的正确方法是什么?

3 个答案:

答案 0 :(得分:1)

我将使用两种不同的模型:CarsFleet和TrainsFleet。两者都可以扩展Fleet模型,但定义不同的has_many关联。

然后,“汽车”将属于cars_fleet,而“火车”将属于trains_fleet。

答案 1 :(得分:1)

这就是polymorphic relationships的作用。

一个Fleet可以有多个vehicles,而一个Vehicle可以是CarTrain,而且重要的是不能同时存在。

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

这样,您可以调用fleet.vehicles,而不必担心课程。

此代码未经测试,但可以使您更容易理解,这是解决问题的最Railsy方式。

答案 2 :(得分:0)

您可以添加模型验证来检查:

class Fleet < ApplicationRecord
  has_many :cars
  has_many :trains

  validates :cars, absence: true, if: -> { trains.any? }
  validates :trains, absence: true, if: -> { cars.any? }
end

以上内容应阻止有车厢和火车的车队得救。但是,您仍然可以分别创建汽车和火车,并将它们链接到车队。

# 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

在上述情况下,我们还要在创建汽车或火车时触发车队验证。为此,请添加validates_associated

validates_associated :fleet

CarTrain模型中。现在,这应保留上述要保存的汽车和火车。


请注意,此答案不会阻止任何与SQL相关的问题,并且从技术上讲,数据库中仍然允许记录。如果您不希望这样做,则必须构建一个运行AFTER INSERTAFTER UPDATE的触发器。由于这与SQL有关,因此我建议您问一个新问题,如果您在触发器创建方面遇到任何问题。提及所使用的数据库,因为对于所有数据库类型(MySQL,SQL Server等),触发器语法都不相同。

相关问题