我目前具有以下模型结构和关系
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执行此操作的正确方法是什么?
答案 0 :(得分:1)
我将使用两种不同的模型:CarsFleet和TrainsFleet。两者都可以扩展Fleet模型,但定义不同的has_many
关联。
然后,“汽车”将属于cars_fleet,而“火车”将属于trains_fleet。
答案 1 :(得分:1)
这就是polymorphic relationships的作用。
一个Fleet
可以有多个vehicles
,而一个Vehicle
可以是Car
或Train
,而且重要的是不能同时存在。
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
在Car
和Train
模型中。现在,这应保留上述要保存的汽车和火车。
请注意,此答案不会阻止任何与SQL相关的问题,并且从技术上讲,数据库中仍然允许记录。如果您不希望这样做,则必须构建一个运行AFTER INSERT
和AFTER UPDATE
的触发器。由于这与SQL有关,因此我建议您问一个新问题,如果您在触发器创建方面遇到任何问题。提及所使用的数据库,因为对于所有数据库类型(MySQL,SQL Server等),触发器语法都不相同。