在Ruby on Rails中一次更新排名/优先级

时间:2013-11-18 07:40:02

标签: ruby-on-rails ruby

我正在开发Ruby on Rails中的个人项目,其中我有一个歌曲模型,其中有一个名为priority的字段。用户可以将歌曲添加到播放列表并为每首歌曲设置优先级,这决定了歌曲的播放顺序。我在这里遇到的问题是,我需要独特的优先事项。

因此,如果我有一首包含8首歌曲的播放列表,并且我正在添加优先级为4的歌曲编号9,则剩余的歌曲应该更新其优先级。任何人都可以建议最好的解决方法是什么?

3 个答案:

答案 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,但是我们会有效地锁定该查询之间的优先级更新并更新优先级列表。我想你可以暂时将它设置为一个大的随机数,以避免这种不太可能的冲突。

请看这里为什么这个特别棘手:

Reordering an ordered list

答案 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