Schienen-Modell mit foreign_key und Verknüpfungstabelle
-
05-07-2019 - |
Frage
Ich versuche, ein Modell für eine Ruby on Rails-Projekt zu erstellen, die Beziehungen zwischen den verschiedenen Wörtern aufbaut. Betrachten Sie es als ein Wörterbuch, in dem die „Links“ zwischen zwei Wörtern zeigt, dass sie synonym verwendet werden können. Meine DB sieht etwa so aus:
Words
----
id
Links
-----
id
word1_id
word2_id
Wie kann ich eine Beziehung zwischen zwei Wörtern zu erstellen, die Link-Tabelle. Ich habe versucht, das Modell zu erstellen, war aber nicht sicher, wie die Link-Tabelle ins Spiel zu bekommen:
class Word < ActiveRecord::Base
has_many :synonyms, :class_name => 'Word', :foreign_key => 'word1_id'
end
Lösung
In der Regel, wenn Ihr Verband Suffixe wie 1 und 2 hat, ist es nicht richtig eingerichtet. Versuchen Sie, diese für das Word-Modell:
class Word < ActiveRecord::Base
has_many :links, :dependent => :destroy
has_many :synonyms, :through => :links
end
Link Modell:
class Link < ActiveRecord::Base
belongs_to :word
belongs_to :synonym, :class_name => 'Word'
# Creates the complementary link automatically - this means all synonymous
# relationships are represented in @word.synonyms
def after_save_on_create
if find_complement.nil?
Link.new(:word => synonym, :synonym => word).save
end
end
# Deletes the complementary link automatically.
def after_destroy
if complement = find_complement
complement.destroy
end
end
protected
def find_complement
Link.find(:first, :conditions =>
["word_id = ? and synonym_id = ?", synonym.id, word.id])
end
end
Tabellen:
Words
----
id
Links
-----
id
word_id
synonym_id
Andere Tipps
Hmm, das ist eine schwierige Sache. Das ist, weil Synonyme entweder von der word1 ID oder der word2 ID oder beides sein kann.
Wie auch immer, wenn ein Modell für die Verknüpfungstabelle verwenden, müssen Sie die verwenden: durch Option auf den Modellen, die die Link-Tabelle
verwendenclass Word < ActiveRecord::Base
has_many :links1, :class_name => 'Link', :foreign_key => 'word1_id'
has_many :synonyms1, :through => :links1, :source => :word
has_many :links2, :class_name => 'Link', :foreign_key => 'word2_id'
has_many :synonyms2, :through => :links2, :source => :word
end
Das sollte es tun, aber jetzt müssen Sie zwei Stellen überprüfen, um alle Synonyme zu bekommen. Ich würde eine Methode hinzufügen, dass diese innerhalb der Klasse Wort verbunden.
def synonyms
return synonyms1 || synonyms2
end
|| zusammen, um die Ergebnisse ing werden die Arrays verbinden und beseitigen Duplikate zwischen ihnen.
* Dieser Code ist nicht getestet.
Word-Modell:
class Word < ActiveRecord::Base
has_many :links, :dependent => :destroy
has_many :synonyms, :through => :links
def link_to(word)
synonyms << word
word.synonyms << self
end
end
Einstellung :dependent => :destroy
auf der has_many :links
werden alle Links mit diesem Wort assoziiert entfernen, bevor das Wort Datensatz destroy
ing.
Link Modell:
class Link < ActiveRecord::Base
belongs_to :word
belongs_to :synonym, :class_name => "Word"
end
Sie verwenden die neuesten Rails Angenommen, Sie werden nicht den Fremdschlüssel für den belongs_to :synonym
angeben. Wenn ich mich richtig erinnere, das als Standard eingeführt wurde, in Rails 2.
Word-Tabelle:
name
Link-Tabelle:
word_id
synonym_id
ein vorhandenes Wort als Synonym für ein anderes Wort, um eine Verknüpfung:
word = Word.find_by_name("feline")
word.link_to(Word.find_by_name("cat"))
Um ein neues Wort als Synonym für ein anderes Wort zu erstellen:
word = Word.find_by_name("canine")
word.link_to(Word.create(:name => "dog"))
ich es aus einem anderen Blickwinkel betrachten würde; da alle Worte auch sind, sollten Sie eine von ihnen nicht fördern die „beste“ zu sein. Probieren Sie etwas wie folgt aus:
class Concept < ActiveRecord::Base
has_many :words
end
class Word < ActiveRecord::Base
belongs_to :concept
validates_presence_of :text
validates_uniqueness_of :text, :scope => :concept_id
# A sophisticated association would be better than this.
def synonyms
concept.words - [self]
end
end
Jetzt können Sie tun
word = Word.find_by_text("epiphany")
word.synonyms
Der Versuch, Sarah-Lösung stieß ich auf zwei Fragen zu implementieren:
Zum einen die Lösung nicht arbeiten zu wollen, wenn Synonyme zuweisen, indem Sie
word.synonyms << s1 or word.synonyms = [s1,s2]
Löschen Auch Synonyme indirekt nicht richtig funktioniert. Dies liegt daran, Rails nicht die after_save_on_create und after_destroy Rückrufe auslösen, wenn es erstellt automatisch oder löscht den Link-Datensätze. Zumindest nicht in Rails 2.3.5, wo ich versuchte es auf.
after_add und: after_remove Rückrufe im Word-Modell:Dies kann durch Verwendung festgelegt werden
has_many :synonyms, :through => :links,
:after_add => :after_add_synonym,
:after_remove => :after_remove_synonym
Wo die Rückrufe sind Sarah Methoden, leicht angepasst:
def after_add_synonym synonym
if find_synonym_complement(synonym).nil?
Link.new(:word => synonym, :synonym => self).save
end
end
def after_remove_synonym synonym
if complement = find_synonym_complement(synonym)
complement.destroy
end
end
protected
def find_synonym_complement synonym
Link.find(:first, :conditions => ["word_id = ? and synonym_id = ?", synonym.id, self.id])
end
Die zweite Ausgabe der Lösung Sarah ist, dass Synonyme, die also schon haben, wenn sie mit einem neuen Wort miteinander verknüpft ist nicht auf das neue Wort hinzugefügt werden, und umgekehrt. Hier ist eine kleine Änderung, die dieses Problem behebt und stellt sicher, dass alle Synonyme eine Gruppe immer auf alle anderen Synonyme in dieser Gruppe verknüpft sind:
def after_add_synonym synonym
for other_synonym in self.synonyms
synonym.synonyms << other_synonym if other_synonym != synonym and !synonym.synonyms.include?(other_synonym)
end
if find_synonym_complement(synonym).nil?
Link.new(:word => synonym, :synonym => self).save
end
end