2012-03-30 10 views
4

Ich habe eine has_many durch Zuordnung zwischen einem Song-Modell und einem Künstlermodell. Mein Code sieht so etwas wie diesesRails has_many durch Vermeidung von Doppelarbeit

SongArtistMap Modell

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

Artist Modell

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

validates_presence_of :name 
end 

Song-Modell

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

ich ein Formular, in dem ein Benutzer ein Lied einreicht und tritt im Liedtitel und im Liedkünstler.

Also, wenn ein Benutzer einen Song und meine Künstler Tabelle nicht bereits den Künstler für den Song, den ich es, dass Künstler und richten Sie die Karte in SongArtistMap

erstellen möchten Wenn ein Benutzer einen Song mit einem einreicht Künstler, der bereits in der Künstler-Tabelle ist Ich möchte nur die SongArtistMap erstellt aber der Künstler nicht dupliziert.

Zur Zeit jedes Mal ein Benutzer einen Song ein neuer Künstler in meiner Künstler-Tabelle erstellt wird, selbst wenn die gleiche ist bereits vorhanden und ein SongArtistMap für diesen duplizierten Künstler erstellt.

Irgendeine Idee, wie man dieses Problem angeht? Ich habe das Gefühl, dass Rails wahrscheinlich einen einfachen kleinen Trick hat, um das bereits eingebaute zu beheben. Danke!

+2

Sie kennen die Methode finden? Sie kennen die Methode erstellen? Nun, Rails hat eine Methode find_or_create_by_attribute! Also in Ihrem Fall könnten Sie find_or_create_by_name verwenden.Da Sie verschachtelte Attribute verwenden ... [Akzeptiert verschachtelte Attribute für Suchen oder Erstellen] (http://stackoverflow.com/questions/3579924/acceps-nested-attributes-for-with-find-or-create) . Also, das ist eine doppelte Frage. – Ashitaka

Antwort

1

Ok Ich habe dies vor einer Weile herausgefunden und poste vergessen zu. Also hier ist, wie ich mein Problem behoben habe. Zuerst erkannte ich, dass ich keine has_many through Beziehung haben musste.

Was ich wirklich brauchte, war ein has_and_belongs_to_many Beziehung. Ich habe das eingerichtet und den Tisch dafür gemacht.

Da ist in meinem Artists Modell habe ich dieses

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 

Und in meinem Song Modell habe ich dieses

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

Und das tat genau das, was ich wollte.

0

Ich verwende ein Verfahren, bei dem Modell der Tabelle die beiden anderen durchlaufen, das heißt mit before_create genannt. Dies kann wahrscheinlich viel besser und schneller gemacht werden.

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

Versuchen Sie folgendes:

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 

Wir sind im Wesentlichen Schienen durch Über Laden der reject_if Funktion austricksen (wie wir nie true zurück).

Sie können dies weiter optimieren durch Groß- und Kleinschreibung-Lookup (nicht erforderlich, wenn Sie auf MySQL sind)

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

ich habe es ausprobiert es scheint nicht effektiv zu sein, ich bekomme immer noch doppelte Künstler erstellt. – Dan

+0

Debuggen Sie, indem Sie 'p artist' hinzufügen, bevor Sie false zurückgeben. Prüfen Sie, ob die ID richtig eingestellt ist. –

+0

Ich füge p Künstler vor der Rückkehr falsch, aber ich bekomme nichts. Soll diese Rückkehr irgendwo auf dem Bildschirm oder in einem Log angezeigt werden? Auch hier ist das Serverprotokoll, wenn ich das Formular übermittle http://pastebin.com/AfwxRack – Dan

Verwandte Themen