Ruby on rails 在Rails中保存关联记录的顺序有很多:通过关联

Ruby on rails 在Rails中保存关联记录的顺序有很多:通过关联,ruby-on-rails,activerecord,associations,ruby-on-rails-plugins,has-many-through,Ruby On Rails,Activerecord,Associations,Ruby On Rails Plugins,Has Many Through,我正在开发一个Rails插件,它包括一种通过关联修改has_many:中关联记录顺序的方法。假设我们有以下型号: class Playlist < ActiveRecord::Base has_many :playlists_songs, :dependent => :destroy has_many :songs, :through => :playlists_songs end class Song < ActiveRecord::Base has_ma

我正在开发一个Rails插件,它包括一种通过关联修改has_many:中关联记录顺序的方法。假设我们有以下型号:

class Playlist < ActiveRecord::Base
  has_many :playlists_songs, :dependent => :destroy
  has_many :songs, :through => :playlists_songs
end

class Song < ActiveRecord::Base
  has_many :playlists_songs, :dependent => :destroy
  has_many :playlists, :through => :playlists_songs
end

class PlaylistsSong < ActiveRecord::Base
  belongs_to :playlist
  belongs_to :song
end
class Playlist:销毁
有许多:歌曲,:至=>:播放列表\u歌曲
结束
类歌曲:销毁
有许多:播放列表,:至=>:播放列表\u歌曲
结束
类playlysong
如果我们更改播放列表中歌曲的顺序(例如,
@Playlist.Songs.rotate!
),Rails不会触及playlists\u Songs表中的记录(我使用的是Rails 3.1),这是有意义的。我想调用Playlist的songs=method保存歌曲的顺序,也许可以通过删除playlists\u歌曲中的相关现有行并按正确的顺序创建新行(以便在检索它们时可以使用
:order=>“id”
)或者在歌曲播放列表中添加sort:integer列,并相应地更新这些值

我没有看到任何回调(例如,在添加之前)允许这样做。实际上,相关的方法似乎是,而且,但我不知道下一步最好的方法是什么。有没有一种方法可以扩展或安全地覆盖这些方法中的一种,以实现我正在寻找的功能(最好只针对特定的关联),或者有没有其他更好的方法来实现这一点?

您看过吗?它是最古老的rails插件之一,旨在处理此类问题

它不是按
id
排序,而是按位置列排序。然后,这仅仅是更新位置的问题,而不是更改
id
或删除/替换记录的麻烦事

在您的情况下,只需将
位置
整数列添加到
播放歌曲
,然后:

class PlayListSong
  acts_as_list :scope => :play_list_id
end
正如您在评论中指出的那样,
中的方法充当列表
主要作用于列表中的单个项目,并且没有现成的“重新排序”功能。我不建议篡改
replace_记录
来执行此操作。使用与插件相同的position列编写方法会更简洁、更明确。比如说

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

这里有一位老铁路司机介绍了acts_as_的名单:谢谢你的提示;我以前看过acts_as_列表,现在我只是尝试一下。不幸的是,它无法解决加入模型的记录在
@playlist.songs.rotate期间未被更新的问题。如果从@playlist.Songs添加或删除歌曲,位置会更新,但如果仅更改歌曲的顺序,则不会更改任何内容。这是在playlassong中定义的
acts\u as\u list:scope=>:playlist\u id
中。如果我遗漏了另一个选项,请让我知道,但我在acts_as_的来源列表中没有看到任何与上述问题相关的内容。其他想法?谢谢你的想法;不幸的是,在仍然使用
CollectionAssociation::writer
的情况下,没有办法保持顺序,但这样可能更安全。这似乎是一个
重新排序
-style方法可能是下一个最好的解决方案,但如果其他人稍后看到这一点并对此有其他想法,请随时与我们分享。