我有一个标签系统上的多个模型是链接在一起。
系统的工作原理如下:
- 一个顶部有很多中部
- 一个中间有很多低
*顶部、中部和底部有许多标记 - 与Top级别关联的标记应该限定与之关联的每个Middle和Low。
- 同样的道理也适用于与Middle关联的标记,与之关联的每个Low都将从标记“继承”。
这个机制不是在数据库级别上,最后在涉及数据库的方面,Tops、Middles和Lows都有自己的标记集合,并且我最初在每个模型上实现了示例方法,这样当你调用例如low_instance.all_tags
时,它会将其父Middles的标记集合和它的一个Top的标记集合连接起来。
以下是模型的外观:
# ______________________________
# / \
# (1) (*)
# [Top] (1) __ (*) [Middle] (*) __ (*) [Low]
# (*) (*) (*)
# \_______________ | ______________/
# |
# *
# [Tags]
class Low < ApplicationRecord
has_many :low_tags, dependent: :destroy
has_many :tags, through: :low_tags
has_many :middle_foos, dependent: :destroy
has_many :middles, through: :middle_foos
end
class Middle < ApplicationRecord
belongs_to :top
has_many :middle_tags, dependent: :destroy
has_many :tags, through: :middle_tags
has_many :middle_lows, dependent: :destroy
has_many :lows, through: :middle_lows
end
class Top < ApplicationRecord
has_many :middles, dependent: :destroy
has_many :lows, dependent: :destroy
has_many :top_tags, dependent: :destroy
has_many :tags, through: :top_tags
end
### Join tables
class MiddleLow < ApplicationRecord
belongs_to :middle
belongs_to :low
end
class LowTag < ApplicationRecord
belongs_to :low
belongs_to :tag
end
class MiddleTag < ApplicationRecord
belongs_to :middle
belongs_to :tag
end
class TopTag < ApplicationRecord
belongs_to :top
belongs_to :tag
end
问题是我希望能够使用Ransackgem搜索我的Low,并使用Low的完整标签集合(它的self标签,加上从父标签Middles和Top继承的标签)
- 问题 *:Ransack只适用于
ActiveRecord::Relations
。所以从Ransack的Angular 来看,我只能使用它们的self-tag搜索我的Lows,而不是完整的继承集合,因为这在数据库级别上不存在。
我想实现的这个问题的最初解决方案是在数据库级别上添加一个“复制”完整标签集合,该集合与其余标签一起更新,我可以用它来使用Ransack进行搜索。
但是我确信我不必向数据库中添加任何内容,因为所有信息都已经在连接表中了,我不想复制这些信息,我认为这不是很酷,而且会使代码库更难理解。
我已经看到potential solutions使用有许多这样的作用域:
has_many :all_tags, ->(low) {
unscope(.........).
left_joins(..........).
where(.........)
# Returs self tags (Low) + tags from associated Middles + tags from the Top
}
我很肯定这是最好的解决方案,但是我真的不擅长数据库查询,尤其是有这么多模型和连接表的时候。我很困惑,似乎找不到什么可以放在那个范围内,这样我就可以得到这个完整的标签集合。
因此,如果有人对此有线索,任何帮助将不胜感激!
顺便说一下,使用Rails 6.1和Ruby 2.7
1条答案
按热度按时间lymnna711#
最后找到了我想构造的查询的解决方案。
作用域如下所示:
在
low
的任何执行严修上呼叫xxx.full_tags
,会从它所属的每个middle
传回tags
的整个集合,加上它所属的top
的集合,再加上它自己的tags
,而且相异会使它成为唯一的集合。话虽如此,这并没有完全解决我的问题,因为整个目的是将这个作用域has_many关系作为Ransack gem使用的一个属性传递,以便从我的
Low
模型的完整继承的标记集合中过滤掉它们。当我发现Ransack在搜索关联时会执行急切的加载时,我感到非常失望:Rails不支持对指定范围的关联进行即时加载
所以我最终为我的标签系统实现了一个完全不同的解决方案。但是嘿,我学到了很多。