在Rails中寻找自我参照关系中的后代

时间:2015-07-31 14:53:57

标签: ruby-on-rails ruby activerecord

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

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的图片。要获得身份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. 因为我跟踪Image上的所有活动,通过将Image转换为ImageVersion,它的引用将在Activity表中丢失(它的类和id会发生变化)。
    2. 人们一次创建多个新图片(他们不会逐个更新),只有在他们插入后我才能进行版本控制,这是一个昂贵的过程。这意味着默认情况下将创建新图像。由于上传的机制,将它们转换为版本并更新原始文件非常麻烦。

1 个答案:

答案 0 :(得分:0)

我完全同意您应该将ImageVersion移动到新模型而不是创建此树。

它会简化事情,并且(在我看来)会是一种更好的方法。

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

希望它有所帮助。