2012-03-30 2 views
4

나는 노래 모델과 아티스트 모델 사이에 has_many through association 셋업을 가지고있다. 내 코드 보인다 나는 사용자가 노래를 제출하고 입력 양식을 가지고이레일즈가 중복을 피하면서 has_many

SongArtistMap 모델

class SongArtistMap < ActiveRecord::Base 
belongs_to :song 
belongs_to :artist 
end 

아티스트 모델

class Artist < ActiveRecord::Base 
has_many :song_artist_maps 
has_many :songs, :through => :song_artist_maps 

validates_presence_of :name 
end 

노래 모델

class Song < ActiveRecord::Base 
    has_many :song_artist_maps 
    has_many :artists, :through => :song_artist_maps 
    accepts_nested_attributes_for :artists 
end 

같은 노래 제목과 노래 아티스트에서.

그래서 사용자는 노래를 제출하고 사용자가 함께 노래를 제출하면 내 아티스트 테이블은 이미 내가 그 작가 및 설정

SongArtistMap

에서지도를 생성 할 노래의 아티스트가없는 경우 아티스트 테이블에 이미있는 아티스트 나는 SongArtistMap을 만들고 싶지만 아티스트는 복제하지 않기를 바란다.

현재 사용자가 노래를 제출할 때마다 동일한 아티스트 테이블이 이미 존재하고 해당 복제 아티스트에 대해 SongArtistMap이 만들어 졌더라도 내 아티스트 테이블에 새 아티스트가 만들어집니다.

이 문제를 해결하는 방법에 대한 아이디어가 있으십니까? 난 레일 아마 이미 내장 된이 문제를 해결하기 위해 몇 가지 간단한 트릭을 느낀다. 감사합니다!

+2

검색 방법을 알고 계십니까? 네가 만드는 방법 알아? 글쎄, 레일스 find_or_create_by_attribute 메소드가 있습니다! 따라서 귀하의 경우에는 find_or_create_by_name을 사용할 수 있습니다.그러나 중첩 된 특성을 사용하고 있기 때문에 ... [찾기 또는 만들기와 함께 중첩 된 특성 허용] (http://stackoverflow.com/questions/3579924/accepts-nested-attributes-for-with-find-or-create) . 그래, 이건 중복 된 질문이다. – Ashitaka

답변

1

확인을 수행하여이를 최적화 할 수 있습니다. 그래서 여기에 내 문제를 해결했습니다. 우선 나는 has_many through 관계가 필요 없다는 것을 깨달았습니다.

정말 필요한 것은 has_and_belongs_to_many 관계입니다. 나는 그것을 설치하고 그것을위한 테이블을 만들었다.

그런 다음 내 Artists 모델에서 나는이

def self.find_or_create_by_name(name) 
    k = self.find_by_name(name) 

    if k.nil? 
    k = self.new(:name => name) 
    end 

    return k 
end 

을 추가 그리고 내 Song 모델에서 나는이

before_save :get_artists 
def get_artists 
    self.artists.map! do |artist| 
    Artist.find_or_create_by_name(artist.name) 
    end 
end 

을 추가 그게 내가 원하는 정확히 무엇을했다.

0

나는 before_create와 함께 호출되는 다른 두 가지가 진행되는 테이블의 모델에서 메서드를 사용합니다. 이것은 아마도 훨씬 더 깔끔하고 빠르게 만들 수 있습니다.

before_create :ensure_only_one_instance_of_a_user_in_a_group 

    private 

    def ensure_only_one_instance_of_a_user_in_a_group 
    user = User.find_by_id(self.user_id) 
    unless user.groups.empty? 
     user.groups.each do |g| 
     if g.id == self.group_id 
      return false 
     end 
     end 
    end 
    return true 
    end 
0

이 시도 : 우리는 기본적으로 (우리가 true를 반환하지로) 오버 로딩 reject_if 기능을하여 레일을기만하는

class Song < ActiveRecord::Base 
    has_many :song_artist_maps 
    has_many :artists, :through => :song_artist_maps 
    accepts_nested_attributes_for :artists, :reject_if => :normalize_artist 


    def normalize_artist(artist) 
    return true if artist['name'].blank? 
    artist['id'] = Artist.find_or_create_by_name(artist['name']).id 
    false # This is needed 
    end 
end 

.

당신은 더 나는이 잠시 전에 파악 및 게시하는 것을 잊었다있어 (당신이 MySQL을 경우에는 필요하지 않음) 대소 문자를 구분 조회를

artist['id'] = ( 
    Artist.where("LOWER(name) = ? ", artist['name'].downcase).first ||  
    Artist.create(:name => artist['name']) 
    ).id 
+0

나는 이것을 시험해 보았다. 효과적이지는 않지만, 나는 여전히 중복 된 아티스트를 만들었다. – Dan

+0

false를 반환하기 전에'p artist'를 추가하여 디버그하십시오. id가 올바르게 설정되어 있는지 확인하십시오. –

+0

false를 반환하기 전에 p 아티스트를 추가하지만 아무것도 얻지 못합니다. 그 반환은 화면이나 어딘가에 로그에 표시되어야합니까? 또한 양식 http://pastebin.com/AfwxRack을 제출하면 서버 로그가 있습니다. – Dan

관련 문제