我有两个型号,Song和Show。 “显示”是一个有序的歌曲列表,其中可以多次列出同一首歌曲。
也就是说,Show中某个地方应该有一个有序数组(或散列或任何东西),它可以包含Song1,Song2,Song1,Song3,并允许从该数组重新排序,插入或删除。
我无法弄清楚如何使用ActiveRecord关联建模。我猜我需要某种特殊的连接表和索引列,但除了开始直接编写我的SQL之外,还有办法用Rails关联吗?
我现在拥有的一些代码(但无法正常工作):
class Song < ActiveRecord::Base
attr_accessible :title
has_and_belongs_to_many :shows
end
class Show < ActiveRecord::Base
attr_accessible :date
has_and_belongs_to_many :songs
end
song1 = Song.create(title: 'Foo')
song2 = Song.create(title: 'Bar')
show1 = Show.create(date: 'Tomorrow')
show1.songs << song1 << song2 << song1
puts "show1 size = #{show1.songs.size}" # 3
show1.delete_at(0) # Should delete the first instance of song1, but leave the second instance
puts "show1 size = #{show1.songs.size}" # 2
show1.reload
puts "show1 size = #{show1.songs.size}" # 3 again, annoyingly
插入可能如下所示:
show1.songs # Foo, Bar, Foo
song3 = Song.create(title: 'Baz')
show1.insert(1, song3)
show1.songs # Foo, Baz, Bar, Foo
重新排序可能(有点神奇)看起来像:
show1.songs # Foo, Bar, Foo
show1.move_song_from(0, to: 1)
show1.songs # Bar, Foo, Foo
答案 0 :(得分:0)
您使用联接表的想法走在正确的轨道上:
class Song < ActiveRecord::Base
attr_accessible :title
has_many :playlist_items
has_many :shows, :through => :playlist_items
end
class PlaylistItem < ActiveRecord::Base
belongs_to :shows #foreign_key show_id
belongs_to :songs #foreign_key song_id
end
class Show < ActiveRecord::Base
attr_accessible :date
has_many :playlist_items
has_many :songs, :through => :playlist_items
end
然后您可以执行user.playlist_items.create :song => Song.last
答案 1 :(得分:0)
我目前的解决方案是has_many:through和acts_as_list的组合。找到正确组合两者的信息并不是最容易的事情。例如,其中一个障碍是acts_as_list使用从1开始的索引,而ActiveRecord关联创建的类似数组的方法从0开始。
这是我的代码如何结束的方式。请注意,我必须指定显式方法来修改连接表(对于大多数方法而言);我不确定是否有更清洁的方法让这些工作。
class Song < ActiveRecord::Base
attr_accessible :title
has_many :playlist_items, :order => :position
has_many :shows, :through => :playlist_items
end
class PlaylistItem < ActiveRecord::Base
attr_accessible :position, :show_id, :song_id
belongs_to :shows
belongs_to :songs
acts_as_list :scope => :show
end
class Show < ActiveRecord::Base
attr_accessible :date
has_many :playlist_items, :order => :position
has_many :songs, :through => :playlist_items, :order => :position
def song_at(index)
self.songs.find_by_id(self.playlist_items[index].song_id)
end
def move_song(index, options={})
raise "A :to option is required." unless options.has_key? :to
self.playlist_items[index].insert_at(options[:to] + 1) # Compensate for acts_as_list starting at 1
end
def add_song(location)
self.songs << location
end
def remove_song_at(index)
self.playlist_items.delete(self.playlist_items[index])
end
end
我添加了一个位置&#39;列到我的播放列表项目&#39;表,根据acts_as_list附带的说明。值得注意的是,我必须深入了解acts_as_list的API以找到insert_at方法。