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

Words
----
id

Links
-----
id
word1_id
word2_id

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

class Word < ActiveRecord::Base
  has_many :synonyms, :class_name => 'Word', :foreign_key => 'word1_id'
end
有帮助吗?

解决方案

通常,如果您的关联具有后缀(例如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

其他提示

嗯,这是一个棘手的问题。这是因为同义词可以来自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

|将结果放在一起将加入数组并消除它们之间的重复。

*此代码未经测试。

单词模型:

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 =&gt; : has_many:links 上的:destroy 将在 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"))

我从不同的角度看待它;因为所有单词都是同义词,所以不应该将它们中的任何一个宣传为“最佳”。尝试这样的事情:

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

尝试实施Sarah的解决方案我遇到了两个问题:

首先,当想要通过执行

分配同义词时,解决方案不起作用
word.synonyms << s1 or word.synonyms = [s1,s2]

间接删除同义词也无法正常工作。这是因为当Rails自动创建或删除链接记录时,它不会触发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

回调是Sarah的方法,稍作调整:

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解决方案的第二个问题是,当与新单词链接在一起时,其他单词已经具有的同义词不会添加到新单词中,反之亦然。 这是一个小修改,修复了这个问题,并确保组的所有同义词始终链接到该组中的所有其他同义词:

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 
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top