Вы смотрели на acts_as_list ?Это один из самых старых плагинов рельсов, предназначенный для решения подобных проблем.
Вместо сортировки по id
сортировка выполняется по позиционному столбцу.Тогда это просто вопрос обновления позиции, а не грязный бизнес по изменению id
или удалению / замене записей.
В вашем случае вы просто добавили бы position
целочисленный столбец к PlayListSong
, затем:
class PlayListSong
acts_as_list :scope => :play_list_id
end
Как вы указали в комментариях, методы в acts_as_list
в основном работают с отдельными элементами в списке, и нет функции «переупорядочить» из коробки.Я не рекомендовал бы вмешиваться с replace_records
, чтобы сделать это.Было бы чище и яснее написать метод, использующий тот же столбец позиции, что и плагин.Например.
class PlayList
# It makes sense for these methods to be on the association. You might make it
# work for #songs instead (as in your question), but the join table is what's
# keeping the position.
has_many :play_list_songs, ... do
# I'm not sure what rotate! should do, so...
# This first method makes use of acts_as_list's functionality
#
# This should take the last song and move it to the first, incrementing
# the position of all other songs, effectively rotating the list forward
# by 1 song.
def rotate!
last.move_to_top unless empty?
end
# this, on the other hand, would reorder given an array of play_list_songs.
#
# Note: this is a rough (untested) idea and could/should be reworked for
# efficiency and safety.
def reorder!(reordered_songs)
position = 0
reordered_songs.each do |song|
position += 1
# Note: update_column is 3.1+, but I'm assuming you're using it, since
# that was the source you linked to in your question
find(song.id).update_column(:position, position)
end
end
end
end