1

我正在尝试为 ruby​​ on rails 项目创建一个模型,该模型在不同单词之间建立关系。把它想象成一本字典,其中两个词之间的“链接”表明它们可以同义使用。我的数据库看起来像这样:

Words
----
id

Links
-----
id
word1_id
word2_id

如何使用链接表在两个单词之间建立关系。我试图创建模型,但不确定如何让链接表发挥作用:

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

应该这样做,但现在您必须检查两个位置以获取所有同义词。我会在 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 => :destroyhas_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

尝试实施 Sarah 的解决方案时,我遇到了 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

The second issue of Sarah's solution is that synonyms that other words already have when linked together with a new word are not added to the new word and vice versa. Here is a small modification that fixes this problem and ensures that all synonyms of a group are always linked to all other synonyms in that group:

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 回答