Пытаясь реализовать решение Сары, я столкнулся с двумя проблемами:
Во-первых, решение не работает при желании назначить синонимы, выполнив
word.synonyms << s1 or word.synonyms = [s1,s2]
Также косвенное удаление синонимов не работает должным образом. Это связано с тем, что Rails не запускает обратные вызовы after_save_on_create и after_destroy при автоматическом создании или удалении записей Link. По крайней мере, в Rails 2.3.5, где я это попробовал.
Это можно исправить с помощью обратных вызовов: after_add и: after_remove в модели Word:
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
Вторая проблема решения Сары заключается в том, что синонимы, которые уже есть у других слов, когда они связаны вместе с новым словом, не добавляются к новому слову и наоборот.
Вот небольшая модификация, которая решает эту проблему и гарантирует, что все синонимы группы всегда связаны со всеми другими синонимами в этой группе:
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