रेल पर has_many संबंध डिफ़ॉल्ट रूप से एक गुंजाइश का उपयोग करें


81

मान लीजिए कि मेरे पास निम्न वर्ग हैं

class SolarSystem < ActiveRecord::Base
  has_many :planets
end

class Planet < ActiveRecord::Base
  scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end

Planetएक गुंजाइश है life_supportingऔर SolarSystem has_many :planets। मैं अपने has_many संबंध को परिभाषित करना चाहूंगा ताकि जब मैं solar_systemसभी संबद्ध लोगों से पूछूं planets, तो यह life_supportingगुंजाइश अपने आप लागू हो जाए। अनिवार्य रूप से, मैं चाहूंगा solar_system.planets == solar_system.planets.life_supporting

आवश्यकताओं को

  • मैं नहीं बदलना चाहते हैं scope :life_supportingमें Planetकरने के लिए

    default_scope where('distance_from_sun > ?', 5).order('diameter ASC')

  • मैं भी जोड़ने के लिए नहीं होने से दोहराव को रोकने के लिए चाहते हैं SolarSystem

    has_many :planets, :conditions => ['distance_from_sun > ?', 5], :order => 'diameter ASC'

लक्ष्य

मुझे कुछ पसंद है

has_many :planets, :with_scope => :life_supporting

संपादित करें: काम के आसपास

जैसा कि @phoet ने कहा, हो सकता है कि ActiveRecord का उपयोग करके डिफ़ॉल्ट गुंजाइश हासिल करना संभव न हो। हालाँकि, मुझे दो संभावित काम मिल गए हैं। दोनों दोहराव को रोकते हैं। पहला, लंबे समय तक, स्पष्ट पठनीयता और पारदर्शिता बनाए रखता है, और दूसरा एक सहायक प्रकार विधि है जिसका आउटपुट स्पष्ट है।

class SolarSystem < ActiveRecord::Base
  has_many :planets, :conditions => Planet.life_supporting.where_values,
    :order => Planet.life_supporting.order_values
end

class Planet < ActiveRecord::Base
  scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end

एक अन्य समाधान जो बहुत अधिक क्लीनर है, बस निम्नलिखित विधि को इसमें जोड़ना है SolarSystem

def life_supporting_planets
  planets.life_supporting
end

और solar_system.life_supporting_planetsजहाँ भी आप उपयोग करना चाहते हैं उसका उपयोग करने के लिए solar_system.planets

न तो सवाल का जवाब देता है, इसलिए मैंने उन्हें यहां रखा क्योंकि काम के आसपास किसी और को इस स्थिति का सामना करना चाहिए।


2
आपके वर्कअराउंड का उपयोग करते हुए where_vales वास्तव में सबसे अच्छा उपलब्ध समाधान है और एक स्वीकृत जवाब के लायक है
विक्टर ट्रॉन

where_valuesहोश स्थितियों के साथ काम नहीं कर सकता है: {:cleared => false}... यह हैश की एक सरणी देता है जो ActiveRecord पसंद नहीं करता है। हैक के रूप में, सरणी में पहला आइटम हथियाने वाला काम करता है: Planet.life_supporting.where_values[0]...
नोलन एमी

मैंने पाया कि मुझे इसके where_astबजाय उपयोग करना था where_valuesया where_values_hashजैसा कि मैंने अन्य मॉडल पर दायरे में AREL का उपयोग किया था। एक इलाज काम किया! +1
br3nt

जवाबों:


130

रेल 4 में, Associationsएक वैकल्पिक scopeपैरामीटर है जो एक लैम्ब्डा को स्वीकार करता है जिसे Relation(cf. सक्रिय डॉक्टर के लिए डॉक्टर :: संघों :: ClassMethods ) पर लागू किया जाता है

class SolarSystem < ActiveRecord::Base
  has_many :planets, -> { life_supporting }
end

class Planet < ActiveRecord::Base
  scope :life_supporting, -> { where('distance_from_sun > ?', 5).order('diameter ASC') }
end

रेल 3 में, where_valuesवर्कअराउंड को कभी-कभी where_values_hashबेहतर स्कोपों का उपयोग करके सुधार किया जा सकता है, जहां स्थितियां एकाधिक whereया हैश द्वारा परिभाषित होती हैं (यहां मामला नहीं)।

has_many :planets, conditions: Planet.life_supporting.where_values_hash

तुम रेल 3 समाधान का विस्तार कर सकता है? रेल 4 एक बहुत साफ है!
ऑगस्टिन रिडिंगर जिंज

1
रेल 3 के लिए, मुझे लगता है कि इसे has_many :planets, conditions: Planet.life_supporting.where_values_hashदायरा लागू करने के लिए पढ़ना चाहिए । उत्सुक उतार-चढ़ाव के लिए भी यह सुनहरा है।
नेरोलॉजिस्ट

1
मुझे यह पता चला कि where_values_hashपाठ के साथ काम नहीं करने वाला कठिन तरीका जहाँ क्लॉस होता है, उदाहरण के User.where(name: 'joe').where_values_hashलिए अपेक्षित हैश लौटेगा, जबकि User.where('name = ?', 'Joe').where_values_hashनहीं। इसलिए, ग्रहों के उदाहरण की संभावना विफल हो जाएगी।
नेरफोलॉजिस्ट

1
@nerfologist आखिरी कोड उदाहरण में गलती को इंगित करने के लिए धन्यवाद, मैंने जवाब संपादित किया। आपकी दूसरी टिप्पणी से समझ में आता है, मुझे लगता है कि यह वही है जो मैं उत्तर के अंतिम पैराग्राफ में बता रहा था। मेरे जवाब को संपादित करने के लिए स्वतंत्र महसूस करें यदि आप सीमाओं को स्पष्ट करने का एक स्पष्ट तरीका पा सकते हैं।
user1003545

2
@ GrégoireClermont यह कोई और अधिक रेल 5 में काम कर रहा है
elquimista


1

मैं सिर्फ ActiveRecord में एक गहरा गोता लगाता था और ऐसा नहीं लगता कि क्या इसे वर्तमान कार्यान्वयन के साथ प्राप्त किया जा सकता है has_many। आप एक ब्लॉक को पास कर सकते हैं:conditions लेकिन यह किसी भी तरह के किसी भी सामान को वापस करने के लिए सीमित है।

वास्तव में सरल और पारदर्शी तरीका जो आप चाहते हैं उसे प्राप्त करने के लिए (जो मुझे लगता है कि आप करने की कोशिश कर रहे हैं) रनटाइम पर गुंजाइश लागू करना है:

  # foo.rb
  def bars
    super.baz
  end

यह आपके द्वारा मांगे जाने से दूर है, लेकिन यह सिर्फ काम कर सकता है;)


धन्यवाद phoet! यह काम करेगा , हालांकि यह कोड समीक्षा में थोड़ा अजीब लगेगा। मुझे लगता है कि इसे लागू करने पर मुझे जो फीडबैक मिलेगा, वह इसके बजाय has_manyघोषणा पर दोहराव है, क्योंकि यह स्पष्ट है।
हारून

कोड-समीक्षा के मेरे दृष्टिकोण से, मैं इस विकल्प को शर्तों के दोहराव आदि पर पसंद करूंगा जब तक कि आप इसके लिए क्या करना है, इसके लिए एक परीक्षण प्रदान करते हैं, यह दृष्टिकोण बहुत अधिक है DRY और SRP
phoet

मैं इस तरह से एक विधि का उपयोग करने के खिलाफ सलाह देता हूं जहां एक संघ आमतौर पर इस्तेमाल किया जाएगा। इसके बजाय मैं एसोसिएशन से शर्तों को हटा दूंगा और एक गुंजाइश है जो स्पष्ट रूप से एसोसिएशन पर कहा जाता है। यह भविष्य में अधिक रखरखाव योग्य और अधिक स्पष्ट होगा।
BM5k

उफ, बस एहसास हुआ कि यह पोस्ट वास्तव में पुरानी थी। इसी तरह के एक मुद्दे पर शोध किया।
BM5k
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.