У меня есть модель Image
, которая has_many
. Версия также является изображением, устанавливающим как самореферентное отношение.Поиск потомков в самореференциальных отношениях в Rails
class Image < ActiveRecord::Base
belongs_to :parent, class_name: 'Image'
has_many :versions, class_name: 'Image', foreign_key: :parent_id
end
Когда новый образ создается обратный вызов ищет дб для образа, который имеет такое же имя. Если он найдет один, он установит свой parent_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
Это еще только получает изображение с идентификатором 2, а не целое дерево спуски. У меня есть два известных варианта:
- Используйте обратный вызов для обновления всех изображений с тем же именем, но я бы предпочел не использовать более сложные обратные вызовы.
- Используйте отдельную таблицу для хранения версий. Но это сложно по двум причинам.
- Поскольку я отслеживаю всю активность на изображении, преобразовывая изображение в ImageVersion, его ссылки будут потеряны в таблице Activity (это изменит класс и идентификатор).
- Люди создают несколько новых изображений одновременно (они не обновляются один за другим), и только после того, как они вставлены, я могу сделать управление версиями, что является дорогостоящим процессом. Это означает, что по умолчанию будут созданы новые изображения. Преобразование их в версии и обновление оригинала оказывается очень сложным из-за механики загрузок.
Я бы не сделал это самооценкой, а имел класс «Image» и «ImageVersion». Это сделает логику намного проще, а также отслеживание дедов. Тогда 'Image' будет иметь много': image_versions', и вы могли бы управлять отношениями в этой таблице. В настоящее время технически изображение 2 является единственной другой версией изображения 3, потому что изображение 1 представляет собой версию изображения 2, которая в данный момент больше похожа на родословную. – engineersmnky
Я думаю, что у вас неправильное назначение parent_id. Если вы делаете a.gif id с идентификатором 1, то вы его пересматриваете, а текущее изображение не имеет каких-либо предыдущих ревизий, тогда вы создадите новое изображение с parent_id = 1, тогда ваши следующие изменения могут посмотреть, он имеет parent_id и будет соответствовать ему. Чтобы повторить, исходный файл не должен иметь parent_id. ревизии должны иметь parent_id.Любая ревизия пересмотра будет иметь parent_id предыдущей ревизии. –
@engineersmnky, что моя моя первоначальная идея, но я не могу создать отдельную модель, потому что у меня есть модель Activity, которая отслеживает все, что происходит на изображении. Преобразуя Image в ImageVersion, я должен найти всю активность, принадлежащую старому изображению, и сделать ссылку на ImageVersion. Это возможно, поскольку Activity является полиморфным, но более сложным, чем это решение. –