我正在开发Ruby on Rails中的个人项目,其中我有一个歌曲模型,其中有一个名为priority的字段。用户可以将歌曲添加到播放列表并为每首歌曲设置优先级,这决定了歌曲的播放顺序。我在这里遇到的问题是,我需要独特的优先事项。
因此,如果我有一首包含8首歌曲的播放列表,并且我正在添加优先级为4的歌曲编号9,则剩余的歌曲应该更新其优先级。任何人都可以建议最好的解决方法是什么?
答案 0 :(得分:1)
您是否应该能够使用Song模型中的validates_uniqueness_of约束来实现此目的?
class Song < ActiveRecord::Base
validates :priority, numericality: { only_integer: true }, :uniqueness => {:scope => :playlist_id}
end
这会强制用户键入除已为特定播放列表保存的号码以外的其他号码...
答案 1 :(得分:1)
我实际上在我自己的应用程序中遇到了类似的问题。
这是我的第一次拍摄:
class Playlist
has_many :playlist_songs
has_many :songs, through: :playlist_songs
end
-
class PlaylistSong
before_save :update_priorities, if: :priorities_changed?
def priorities_changed?
new_record? || priority_was != priority
end
def update_priorities
if new_record?
playlist.playlist_songs.update_all("priority = priority+1 where priority >= #{priority}")
else
# ouch. not so simple with unique constraint on priority
end
end
end
唯一约束的问题是:
priorities: 1,2,3
update: 3 -> 1
#> triggers
1 -> 2
2 -> 3
但是已经采用了3(我们将优先级更改为1的当前记录)。我们不能先改为1因为1。我现在唯一的想法是将当前更新的记录设置为非唯一优先级,如999,但是我们会有效地锁定该查询之间的优先级更新并更新优先级列表。我想你可以暂时将它设置为一个大的随机数,以避免这种不太可能的冲突。
请看这里为什么这个特别棘手:
答案 2 :(得分:0)
这是我处理它的方式 - 如果我强制执行唯一性约束,我将不得不采用Damien处理的方式 - 通过分配一些独特的优先级然后更新。所以相反,我决定让我的代码处理唯一性。这就是我所做的:
在为播放列表创建新歌曲时,我在create_new_priorities_for_existing_songs
操作中调用songs#create
-
def self.create_new_priorities_for_existing_songs (song, priority)
song_id = song.id
playlist = song.playlist
all_songs = playlist.songs
all_songs.where("priority >= :priority and id != :song_id", :priority => priority, :song_id => song_id).update_all ("priority = priority+1")
end
我在update_priorities_of_existing_songs
操作中调用songs#update
方法 -
def self.update_priorities_of_existing_songs (song_id, old_priority, new_priority)
return if old_priority == new_priority
song = Song.find(song_id)
playlist = song.playlist
all_songs = playlist.songs
if old_priority < new_priority
all_songs.where("priority > :old_priority and priority <= :new_priority and id != :song_id", :old_priority => old_priority, :new_priority => new_priority, :song_id => song_id).update_all ("priority = priority-1")
elsif old_priority > new_priority
all_songs.where("priority >= :new_priority and priority < :old_priority and id != :song_id", :old_priority => old_priority, :new_priority => new_priority, :song_id => song_id).update_all ("priority = priority+1")
end
end