1

異なる単語間の関係を構築する ruby​​ on rails プロジェクトのモデルを作成しようとしています。これは、2 つの単語間の「リンク」が同義語として使用できることを示す辞書と考えてください。私のDBは次のようになります。

Words
----
id

Links
-----
id
word1_id
word2_id

リンク テーブルを使用して、2 つの単語間の関係を作成するにはどうすればよいですか。モデルを作成しようとしましたが、リンクテーブルを機能させる方法がわかりませんでした:

class Word < ActiveRecord::Base
  has_many :synonyms, :class_name => 'Word', :foreign_key => 'word1_id'
end
4

5 に答える 5

4

一般に、アソシエーションに1や2などのサフィックスが付いている場合、正しく設定されていません。Wordモデルでこれを試してください。

class Word < ActiveRecord::Base
  has_many :links, :dependent => :destroy
  has_many :synonyms, :through => :links
end

リンクモデル:

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

テーブル:

Words
----
id

Links
-----
id
word_id
synonym_id
于 2009-03-08T20:54:05.150 に答える
2

うーん、これはトリッキーです。これは、同義語が word1 id または word2 id またはその両方に由来する可能性があるためです。

とにかく、リンク テーブルにモデルを使用する場合は、リンク テーブルを使用するモデルで :through オプションを使用する必要があります。

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

これで問題ありませんが、すべての同義語を取得するには 2 つの場所をチェックする必要があります。クラス Word 内で、これらを結合するメソッドを追加します。

def synonyms
  return synonyms1 || synonyms2
end

||結果を一緒にすると、配列が結合され、それらの間の重複がなくなります。

*このコードはテストされていません。

于 2009-03-08T17:29:19.370 に答える
2

単語モデル:

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

を設定:dependent => :destroyすると、単語レコードを ing するhas_many :links前に、その単語に関連付けられたすべてのリンクが削除されます。destroy

リンク モデル:

class Link < ActiveRecord::Base
  belongs_to :word
  belongs_to :synonym, :class_name => "Word"
end

最新の Rails を使用していると仮定すると、 の外部キーを指定する必要はありませんbelongs_to :synonym。私の記憶が正しければ、これは Rails 2 で標準として導入されました。

単語表:

name

リンク テーブル:

word_id
synonym_id

既存の単語を同義語として別の単語にリンクするには:

word = Word.find_by_name("feline")
word.link_to(Word.find_by_name("cat"))

新しい単語を別の単語の同義語として作成するには:

word = Word.find_by_name("canine")
word.link_to(Word.create(:name => "dog"))
于 2009-03-09T02:42:24.207 に答える
1

私はそれを別の角度から見ます。すべての単語は同義語であるため、それらのいずれかを「最高」に宣伝するべきではありません。次のようなものを試してください。

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

今、あなたはすることができます

word = Word.find_by_text("epiphany")
word.synonyms
于 2009-03-08T20:40:45.353 に答える
0

サラのソリューションを実装しようとすると、2 つの問題が発生しました。

まず、次のようにして同義語を割り当てたい場合、ソリューションは機能しません

word.synonyms << s1 or word.synonyms = [s1,s2]

また、シノニムを間接的に削除すると、正しく機能しません。これは、Rails が Link レコードを自動的に作成または削除するときに、 after_save_on_create および after_destroy コールバックをトリガーしないためです。少なくとも、私が試したRails 2.3.5ではそうではありませんでした。

これは、Word モデルで :after_add および :after_remove コールバックを使用することで修正できます。

has_many :synonyms, :through => :links,
                    :after_add => :after_add_synonym,
                    :after_remove => :after_remove_synonym

コールバックはサラのメソッドで、わずかに調整されています。

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

Sarah の解決策の 2 番目の問題は、新しい単語と一緒にリンクされたときに他の単語が既に持っている同義語が新しい単語に追加されず、その逆も同様であるということです。この問題を修正し、グループのすべてのシノニムが常にそのグループ内の他のすべてのシノニムにリンクされるようにする小さな変更を次に示します。

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 
于 2011-04-30T10:05:32.553 に答える