2012-12-04 3 views
2

두 가지 모델 Song 및 Show가 있습니다. 쇼는 동일한 노래를 여러 번 나열 할 수있는 정렬 된 노래 목록입니다.중복을 허용하는 정렬 된 모델 연결을 갖는 방법

즉, Song1, Song2, Song1, Song3을 포함 할 수 있고 해당 배열에서 순서 바꾸기, 삽입 또는 삭제가 가능한 Show 어딘가의 정렬 된 배열 (또는 해시 또는 기타)이 있어야합니다.

ActiveRecord 연관성을 사용하여이를 모델링하는 방법을 알 수 없습니다. 나는 인덱스를위한 컬럼을 가진 일종의 특별한 조인 테이블이 필요하다고 생각하지만, SQL을 직접 코딩하는 것을 제외하면 레일즈 연관성을 가지고 이것을 할 수있는 방법이 있는가?

내가 지금 그것을 가지고 (그러나 제대로 작동하지 않습니다) 같은 일부 코드 :

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

내 현재의 솔루션과 같은 물건을 할 수있는 has_many의 조합이다. 이 두 가지 정보를 올바르게 결합하는 정보를 찾는 것이 가장 쉬운 방법은 아니 었습니다. 장애물 중 하나는 예를 들어, 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 

나는 acts_as_list와 함께 제공된 지침에 따라, 내 'playlist_items'테이블에 '위치'열을 추가했다. 필자는 acts_as_list에 대한 API를 파고 들어 insert_at 메소드를 찾아야한다는 사실에 유의할 가치가있다.

0

:

통해 acts_as_list :
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

+0

나는 has_many를 얻고있다 : 티켓은 지나치지 만, 이것은 여전히 ​​habtm과 같은 것처럼 보인다. 쇼의 특정 인덱스에서 노래를 어떻게 삭제합니까? 즉, show.playlist_items.delete_at (4)와 같은 것입니까? – sirbrillig

+0

예, 삭제 방법입니다. 당신은 맞습니다 (둘 다 조인 테이블을 사용합니다)하지만, 당신이 조인 테이블에 직접 접근 할 수 있기 때문에'has_many => : through'를 사용하는 것이 더 낫습니다 (유효성 검사/여분의 속성 등을 추가 할 필요가 있기 때문에). – David

+0

말하자면 위의 habtm에 대한'shows_songs (show_id : integer, song_id : integer)'조인 테이블을 만들었습니까? – David

관련 문제