我正在尝试为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
答案 0 :(得分: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
答案 1 :(得分:2)
无论如何,当使用模型作为链接表时,必须在使用链接表的模型上使用: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
|将结果放在一起将加入数组并消除它们之间的重复。
*此代码未经测试。
答案 2 :(得分: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
上设置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"))
答案 3 :(得分: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
答案 4 :(得分:0)
尝试实施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