درابزون نموذج مع foreign_key وصلة الجدول
-
05-07-2019 - |
سؤال
واني اسعى الى خلق نموذج لروبي على القضبان المشروع أن يبني علاقات بين الكلمات المختلفة. كما أنها تفكر في قاموس فيها "الروابط" بين كلمتين تبين أنها يمكن أن تستخدم بشكل مترادف. بلدي DB يبدو شيئا من هذا القبيل:
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، انها ليست إعداد بشكل صحيح. جرب هذا لنموذج الكلمات:
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 أو هوية WORD2 أو كليهما.
وعلى أي حال، عند استخدام نموذج لجدول ارتباط، يجب استخدام: من خلال الخيار على نماذج التي تستخدم الجدول ارتباط
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
وهذا ينبغي أن نفعل ذلك، ولكن الآن يجب أن تحقق مكانين للحصول على كل المرادفات. وأود أن أضيف طريقة التي انضمت هذه، وورد الدرجة الداخل.
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 => :destroy
على has_many :links
سيزيل جميع الروابط المرتبطة بهذا كلمة قبل destroy
ing سجل كلمة.
وينك نموذج:
class Link < ActiveRecord::Base
belongs_to :word
belongs_to :synonym, :class_name => "Word"
end
وعلى افتراض أنك تستخدم أحدث القضبان، سوف لا يكون لديك لتحديد المفتاح الخارجي للbelongs_to :synonym
. إذا لم تخني، وقدم هذا كمعيار في القضبان 2.
وجدول Word:
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
ومحاولة لتنفيذ حل سارة جئت عبر 2 قضايا:
أولا، والحل لا يعمل عند الرغبة في تعيين المرادفات عن طريق القيام
word.synonyms << s1 or word.synonyms = [s1,s2]
وأيضا حذف المرادفات غير مباشر لا يعمل بشكل صحيح. وذلك لأن القضبان لا تؤدي إلى after_save_on_create وafter_destroy الاسترجاعات عندما يخلق تلقائيا أو حذف السجلات الارتباط. على الأقل ليس في القضبان 2.3.5 حيث حاولت عليه.
ويمكن ان تكون ثابتة هذه باستخدام: رد after_remove في النموذج الكلمات:: after_add و
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