Ruby-on-rails: MOUNTIONS HAS_MANY: من خلال ممكن؟
-
24-09-2019 - |
سؤال
هل من الممكن أن يكون لديك متعددة has_many :through
العلاقات التي تمر عبر بعضها البعض في القضبان؟ تلقيت الاقتراح للقيام بذلك كحل لسؤال آخر نشرته ، لكنني لم أتمكن من عمله.
الأصدقاء الرابطة الدورية من خلال جدول انضمام. الهدف هو إنشاء ملف has_many :through
ل friends_comments
, ، حتى أتمكن من أخذ ملف User
وافعل شيئًا مثل user.friends_comments
للحصول على جميع التعليقات التي أدلى بها أصدقاؤه في استفسار واحد.
class User
has_many :friendships
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
has_many :comments
has_many :friends_comments, :through => :friends, :source => :comments
end
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
end
هذا يبدو رائعًا ، ومن المنطقي ، لكنه لا يعمل بالنسبة لي. هذا هو الخطأ الذي أحصل عليه في الجزء ذي الصلة عندما أحاول الوصول إلى Friends_comments للمستخدم:
ERROR: column users.user_id does not exist
: SELECT "comments".* FROM "comments" INNER JOIN "users" ON "comments".user_id = "users".id WHERE (("users".user_id = 1) AND ((status = 2)))
عندما أقوم فقط بإدخال user.friends ، الذي يعمل ، هذا هو الاستعلام الذي ينفذه:
: SELECT "users".* FROM "users" INNER JOIN "friendships" ON "users".id = "friendships".friend_id WHERE (("friendships".user_id = 1) AND ((status = 2)))
لذلك يبدو أنه ينسى تمامًا الأصل has_many
من خلال علاقة الصداقة ، ثم تحاول استخدام فئة المستخدم كجدول انضمام بشكل غير لائق.
هل أفعل شيئًا خاطئًا ، أم أن هذا ببساطة غير ممكن؟
المحلول
تعديل:
القضبان 3.1 يدعم الجمعيات المتداخلة. على سبيل المثال:
has_many :tasks
has_many :assigments, :through => :tasks
has_many :users, :through => :assignments
ليست هناك حاجة للحل الوارد أدناه. تشير إلى هذه screencast لمزيد من التفاصيل.
الإجابة الأصلية
أنت تمر has_many :through
الارتباط كمصدر لآخر has_many :through
جمعية. لا أعتقد أنه سيعمل.
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
has_many :friends_comments, :through => :friends, :source => :comments
لديك ثلاثة طرق لحل هذه القضية.
1) اكتب امتداد جمعية
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}" do
def comments(reload=false)
@comments = nil if reload
@comments ||=Comment.find_all_by_user_id(map(&:id))
end
end
الآن يمكنك الحصول على تعليقات الأصدقاء على النحو التالي:
user.friends.comments
2) إضافة طريقة إلى User
صف دراسي.
def friends_comments(reload=false)
@friends_comments = nil if reload
@friends_comments ||=Comment.find_all_by_user_id(self.friend_ids)
end
الآن يمكنك الحصول على تعليقات الأصدقاء على النحو التالي:
user.friends_comments
3) إذا كنت تريد أن يكون هذا أكثر كفاءة ثم:
def friends_comments(reload=false)
@friends_comments = nil if reload
@friends_comments ||=Comment.all(
:joins => "JOIN (SELECT friend_id AS user_id
FROM friendships
WHERE user_id = #{self.id}
) AS friends ON comments.user_id = friends.user_id")
end
الآن يمكنك الحصول على تعليقات الأصدقاء على النحو التالي:
user.friends_comments
جميع الطرق ذاكرة التخزين المؤقت للنتائج. إذا كنت تريد إعادة تحميل النتائج ، فافعل ما يلي:
user.friends_comments(true)
user.friends.comments(true)
أو الأفضل من ذلك:
user.friends_comments(:reload)
user.friends.comments(:reload)
نصائح أخرى
هناك مكون إضافي يحل مشكلتك ، وإلقاء نظرة على هذه المدونة.
تقوم بتثبيت البرنامج المساعد مع
script/plugin install git://github.com/ianwhite/nested_has_many_through.git
على الرغم من أن هذا لم ينجح في الماضي ، إلا أنه يعمل بشكل جيد في Rails 3.1 الآن.
لقد وجدت أن إدخال المدونة هذا مفيد: http://geoff.evason.name/2010/04/23/nested-has_many-through-in-rails-or-how-to-do-a-3-table-join/