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
War es hilfreich?

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

verwenden
class 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 destroying.

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 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top