【发布时间】:2022-01-03 04:50:09
【问题描述】:
我正在开发一个小型集合跟踪器,我觉得 STI 可以真正简化这个问题,但似乎普遍的共识是尽可能避免 STI,所以我已经分解了我的模型。目前,它们都是相同的,但我确实有一些不同的元数据,我可以看到自己附加到它们。
无论如何,根是Platform,其中有许多Games、Systems、Peripherals 等,我试图在可过滤的动态表中的视图上显示所有这些关系,可排序和可搜索。
例如,查询可以是@platform.collectables.search(q).order(:name)。
# Schema: platforms[ id, name ]
class Platform < ApplicationRecord
has_many :games
has_many :systems
has_many :peripherals
end
# Schema: games[ id, platform_id, name ]
class Game < ApplicationRecord
belongs_to :platform
end
# Schema: systems[ id, platform_id, name ]
class System < ApplicationRecord
belongs_to :platform
end
# Schema: peripherals[ id, platform_id, name ]
class Peripheral < ApplicationRecord
belongs_to :platform
end
在上面,当我将它们添加到 Collection 时,多态性开始发挥作用:
# Schema: collections[ id, user_id, collectable_type, collectable_id ]
class Collection < ApplicationRecord
belongs_to :user
belongs_to :collectable, polymorphic: true
end
现在,当我查看Platform 时,我希望看到它的所有游戏、系统和外围设备,我称之为收藏品。我将如何查询所有这些同时能够作为一个整体进行排序(即:“名称 ASC”)。下面在理论上可行,但这会改变与数组的关系,这会阻止我在数据库级别进行进一步过滤、搜索或重新排序,因此我无法标记另一个 scope 或 order。
class Platform < ApplicationRecord
...
def collectables
games + systems + peripherals
end
end
我偶然发现了Delegated Types,这听起来像是朝着我正在寻找的方向迈出的一步,但也许我错过了一些东西。
我很想尝试 STI 路线,我认为这些模型差异不大,不同的东西可以存储在 JSONB 列中,因为它主要只是用于填充视图的元数据,而不是真正搜索.基本上是这样的模型,但它似乎很不受欢迎,我觉得我一定错过了什么。
# Schema: collectables[ id, platform_id, type, name, data ]
class Collectable < ApplicationRecord
belongs_to :platform
end
class Platform < ApplicationRecord
has_many :collectables
def games
collectables.where(type: 'Game')
end
def systems
collectables.where(type: 'System')
end
...
end
【问题讨论】:
-
您要克服的实际问题是什么?多态性如何解决这个问题?当一个“集合”看起来只是其部分的总和时,为什么它是必要的?就我个人而言,我觉得 STI 或多态性可能只会使情况复杂化,但也许我不太清楚这个问题。如果这些模型共享某些属性(仅通过命名约定),那很好。如果他们共享演示文稿或方法,您可以通过组合模块简化此逻辑。
-
@engineersmnky 当我需要将收藏品与用户相关联时,多态性开始发挥作用,所以我认为这不是问题的一部分,因为我可以在视图中正确过滤用户集合由多态列。我遇到的问题是,当我想显示与平台相关的所有收藏品时,仍然能够过滤、搜索或排序(动态表)。组合这 3 个对象会将它们变成一个数组,这会阻止我在数据库级别上有效地执行搜索。所以实际上...
@platform.collectables.search(q).order("name desc") -
如果您不想使用 STI,另一种想法是使用 UNION SQL 短语
-
我不认为 number_of_players 是游戏的元数据,它应该是一个属性。我什至不知道 Rails 中存在委托类型,但它们似乎确实是一个合适的解决方案
-
“我没有看到这些模型有太大的不同”——著名的遗言。
标签: ruby-on-rails activerecord