在Rails中查找自引用关系中的后代



我有一个has_many版本的Image模型。版本也是一个映像,设置为一个自引用关系。

class Image < ActiveRecord::Base
  belongs_to :parent, class_name: 'Image'
  has_many :versions, class_name: 'Image', foreign_key: :parent_id
end

当创建一个新映像时,回调将在数据库中搜索具有相同名称的映像。如果它找到一个,它将把它的parent_id设置为新映像的id。这将创建一个树状结构:

| id | name  | parent_id |
--------------------------
|  1 | a.gif |         2 |
|  2 | a.gif |         3 |
|  3 | a.gif |      NULL |
--------------------------

是否有一种简单的方法来检索图像的所有后代?如预期的那样,image.versions找到id为2的图像。为了得到id为1的图像,我必须遍历图像2。

image = Image.find(3)
versions = image.versions # this finds image 2
descendents = versions.each { |v| v.versions } # etc...

我尝试了has_one关系:

  belongs_to :parent, class_name: 'Image'
  has_one :version, class_name: 'Image', foreign_key: :parent_id
  has_many :versions, through: :version

仍然只检索id为2的图像,而不是整个下降树。我有两个已知的选择:

  1. 使用回调更新所有具有相同名称的图像,但我宁愿不使用更复杂的回调。
  2. 使用单独的表来存储版本。但这很复杂,原因有二。
    1. 因为我跟踪图像上的所有活动,通过将图像转换为ImageVersion,其引用将在activity表中丢失(它的类和id将会改变)。
    2. 人们一次创建多个新图像(他们不会一个一个地更新),只有在它们被插入之后,我才能进行版本控制,这是一个昂贵的过程。这意味着默认情况下将创建新映像。由于上传的机制,将它们转换为版本并更新原始版本是非常麻烦的。

我完全同意您应该将ImageVersion移动到一个新模型中,而不是创建这个树。

这将简化事情,这将是(在我看来)一个更好的方法。

但是如果你真的需要这样做,你应该看看这个宝石,我从来没有使用过它,但它似乎正是你所要求的:https://github.com/take-five/activerecord-hierarchical_query

希望能有所帮助。

最新更新