بالنظر إلى مجموعة من كائنات ActiveRecord، هل يمكنني بسهولة جمع علاقاتها من خلال استدعاء الأسلوب؟
-
03-07-2019 - |
سؤال
لنفترض أن لدي الكود التالي:
@sites = Site.find(session[:sites]) # will be an array of Site ids
@languages = Language.for_sites(@sites)
for_sites هو نطاق مسمى في نموذج اللغة الذي يُرجع اللغات المرتبطة بتلك المواقع، وترتبط اللغات بالمواقع التي تستخدم has_many من خلال.الهدف هو أن يكون لدى @languages مجموعة متميزة من اللغات المرتبطة بالمواقع.
بدلاً من استدعاء كائن اللغة في السطر الثاني، أود أن أقول ذلك بشكل مثالي
@sites.languages
وقد عادت لي نفس القائمة.هل هناك أي طريقة للقيام بذلك بشكل نظيف في Rails 2.1 (أو الحافة)؟أعلم أن الارتباطات والنطاقات المسماة يمكنها توسيع كائن المصفوفة ليحتوي على سمات، ولكن ما لم أفتقد شيئًا لا ينطبق هنا.سيكون موضع ترحيب أي مكونات إضافية تقوم بذلك، وليس من الضروري أن تكون أساسية.
المحلول
يمكنك توسيع المصفوفة التي تم إرجاعها بواسطة Site.find.
class Site
def find(*args)
result = super
result.extend LanguageAggregator if Array === result
result
end
end
module LanguageAggregator
def languages
Language.find(:all, :conditions => [ 'id in (?)', self.collect { |site| site.id } ])
end
end
نصائح أخرى
لماذا لا تستخدم name_scopes لكليهما؟
class Site
named_scope :sites, lambda{|ids| :conditions => "id in (#{ids.join(',')})"}
named_scope :languages, :include => :languages ... (whatever your named scope does)
end
يتصل:
Site.sites(session[:sites]).languages
أو، إذا كنت تريد استعادة كائنات اللغة
Site.sites(session[:sites]).languages.collect{|site| site.languages}.flatten
يمكنك أيضًا القيام بذلك مباشرةً على كائن اللغة.أنا أستخدم :joins لأن Rails 2.1 ينقسم و:include إلى استعلامين مما يعني أنه لا يمكننا استخدام المواقع في :conditions
class Language
named_scope :for_sites, lambda{|site_ids| :joins => 'inner join sites on languages.site_id = sites.id' :conditions => "sites.id in (#{site_ids.join(',')})"}
end
يتصل:
Language.for_sites(session[:sites])
في كلا المثالين افترضت أن session[:sites] يتم التحكم فيها بالكامل بواسطتك ولا تخضع لحقن SQL.إذا لم يكن الأمر كذلك، فتأكد من التعامل مع تنظيف بطاقات الهوية
متغير المثيل الخاص بك @sites هو كائن Array وليس Site، لذلك لا أعتقد أنه يمكن استخدام name_scope.يمكنك فتح فئة Array لتحقيق هذا التأثير من خلال (yikes)
class Array
def languages
...
end
end
إذا أضفت أ has_many
أو has_and_belongs_to_many
ربط اللغات بالمواقع، ثم يمكنك استخدام التضمين والقيام بشيء مثل هذا:
Site.find( :all, :conditions =>{:id => session[:sites]}, :include => :languages )
يمكنك إنشاء نطاق مسمى للقيام بالأمر :id => session[:sites]، على سبيل المثال:
class Site
named_scope :for_ids, lambda{ |x| {:conditions => {:id => x }
end
ومن ثم القيام به
Site.for_ids(session[:sites]).find(:all, :include => :languages)
نأمل أن يعطيك هذا بعض الأفكار