方案
我有Media而不是有很多音轨,我想在媒体中存储音轨序列,但对于特定媒体,序列必须是唯一的。因此,例如,Media对象可以具有10个轨道,每个轨道具有1,2,... 10的序列
class Medium < ActiveRecord::Base
has_many :tracks, inverse_of: :medium, dependent: :destroy
end
class Track < ActiveRecord::Base
belongs_to :medium
validates_uniqueness_of :sequence, scope: :medium, message: 'sequence is not unique for the medium'
end
然而,用户可以改变音轨的顺序,例如他们将第二个音轨移动到第8个位置 - 这将导致序列3 - 8的音轨序列减1(分别变为2 - 7)并且序列2的原始轨道成为轨道8.
问题
问题是我不能简单地更改值并保存轨道,因为当然验证失败了。
我能想到的唯一解决方案是:
然而,这似乎效率很低,只适合这种情况。例如,我可以从另一个方向移动轨道,从位置8到位置2。
理想情况下,我希望允许用户更改曲目上的序列并修改其他数据,并且只有一旦满意,才会提交,这将导致调用将调用media.save
的操作。
在Rails中是否有更好的实践来处理这种情况,或者它看起来是如此复杂。将此作为特殊情况处理并将每个更改处理为原子序列是更好的做法 - 意味着在用户更改轨道序列时立即命中服务器(其他轨道属性更改由被调用的父保存处理,即。{{ 1}})
答案 0 :(得分:2)
您可以使用act as list gem来解决排序和重新排序问题。
<强>的Gemfile 强>
gem 'acts_as_list'
<强> medium.rb 强>
class Medium < ActiveRecord::Base
has_many :tracks,
-> { order(sequence: :asc) },
inverse_of: :medium,
dependent: :destroy
end
<强> track.rb 强>
class Track < ActiveRecord::Base
belongs_to :medium
acts_as_list column: :sequence, scope: :medium
end
答案 1 :(得分:1)
您可以在父媒体记录上使用transaction并执行所有更改,包括一个块中的序列重新编号。