Ruby on rails 在具有唯一验证的记录之间交换值

Ruby on rails 在具有唯一验证的记录之间交换值,ruby-on-rails,ruby-on-rails-4,activerecord,Ruby On Rails,Ruby On Rails 4,Activerecord,场景 我的媒体可以有很多音轨,我想在媒体中存储音轨序列,但对于特定媒体,序列必须是唯一的。因此,例如,一个媒体对象可能有10个磁道,每个磁道的序列为1,2。。十, class Medium < ActiveRecord::Base has_many :tracks, inverse_of: :medium, dependent: :destroy end class Track < ActiveRecord::Base belongs_to :medium val

场景

我的媒体可以有很多音轨,我想在媒体中存储音轨序列,但对于特定媒体,序列必须是唯一的。因此,例如,一个媒体对象可能有10个磁道,每个磁道的序列为1,2。。十,

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
class-Medium
但是,用户可以更改轨迹序列,例如,他们将第二个轨迹移动到第8个位置-这将导致序列3-8的轨迹序列递减1(分别变为2-7),序列2的原始轨迹变为轨迹8

问题

问题是我不能简单地更改值并保存曲目,因为验证当然会失败

我能想到的唯一解决办法是:

  • 使用临时但唯一的序列号设置第一个受影响的轨迹并保存
  • 减少其他曲目的序列号并保存它们
  • 用正确的序列号重新分配第一首曲目并保存
  • 然而,这似乎是非常低效的,并且只适合这一种情况。我可以将轨迹从另一个方向移动,例如从位置8移动到位置2

    理想情况下,我希望允许用户更改音轨上的序列并修改其他数据,并且仅在高兴时提交,这将导致调用调用
    media.save
    的操作

    Rails中是否有更好的实践来处理此场景,或者它是否像看上去那样复杂。将此视为一种特殊情况并以原子方式处理对序列的每次更改是否更好?这意味着一旦用户更改了曲目序列(调用父存储处理的其他曲目属性更改,即…
    media.save

    您可以在父媒体记录上使用a并执行所有更改,包括一个块中的序列重新编号。

    您可以在父媒体记录上使用a并执行所有更改,包括一个块中的序列重新编号。

    您可以使用来解决排序和重新排序问题

    Gemfile

    gem 'acts_as_list'
    
    中等。rb

    class Medium < ActiveRecord::Base
      has_many :tracks,
               -> { order(sequence: :asc) },
               inverse_of: :medium,
               dependent: :destroy
    end
    
    class Track < ActiveRecord::Base
      belongs_to :medium
      acts_as_list column: :sequence, scope: :medium
    end
    
    class-Medium{order(sequence::asc)},
    介质的逆,
    依赖::销毁
    终止
    
    track.rb

    class Medium < ActiveRecord::Base
      has_many :tracks,
               -> { order(sequence: :asc) },
               inverse_of: :medium,
               dependent: :destroy
    end
    
    class Track < ActiveRecord::Base
      belongs_to :medium
      acts_as_list column: :sequence, scope: :medium
    end
    
    classtrack
    您可以使用来解决排序和重新排序问题

    Gemfile

    gem 'acts_as_list'
    
    中等。rb

    class Medium < ActiveRecord::Base
      has_many :tracks,
               -> { order(sequence: :asc) },
               inverse_of: :medium,
               dependent: :destroy
    end
    
    class Track < ActiveRecord::Base
      belongs_to :medium
      acts_as_list column: :sequence, scope: :medium
    end
    
    class-Medium{order(sequence::asc)},
    介质的逆,
    依赖::销毁
    终止
    
    track.rb

    class Medium < ActiveRecord::Base
      has_many :tracks,
               -> { order(sequence: :asc) },
               inverse_of: :medium,
               dependent: :destroy
    end
    
    class Track < ActiveRecord::Base
      belongs_to :medium
      acts_as_list column: :sequence, scope: :medium
    end
    
    classtrack
    请详细说明这个答案。Save会自动包装在事务块中,如果我试图从控制台执行此操作,则会抛出验证错误-我添加了
    接受\u嵌套的\u属性\u for:tracks
    ,并调用
    medium。Save
    以测试它。请详细说明此答案。Save自动包装在事务块中,如果我试图从控制台执行此操作,则会抛出验证错误-我添加了
    接受\u嵌套的\u属性\u for:tracks
    ,并调用
    medium.Save
    对其进行测试。哦,这看起来很有希望。。。。等我有机会再打给你,我就得试试。谢谢:)顺便说一句。。你能编辑这个链接吗。。它坏了。。。只需要删除最后几个字符。工作完美,给了我确切的我需要的。。。对于您的解决方案,
    ->{order(sequence::asc)},
    必须在介质的
    逆之前出现。要使用我现有的数据库,我可以使用
    acts\u as\u list column::sequence,scope::medium
    噢,这看起来很有希望。。。。等我有机会再打给你,我就得试试。谢谢:)顺便说一句。。你能编辑这个链接吗。。它坏了。。。只需要删除最后几个字符。工作完美,给了我确切的我需要的。。。对于您的解决方案,
    ->{order(sequence::asc)},
    必须在介质的
    逆之前出现。要使用现有数据库,我可以使用
    acts\u as\u list column::sequence,scope::medium