2015-02-23 10 views
7

स्कॉप्स को शामिल करने वाली मॉडल चिंताओं का उपयोग करके, यह जानने के लिए सबसे अच्छा तरीका क्या है कि नेस्टेड और/या स्वयं-संदर्भ प्रश्नों की संभावना है?उपनाम तालिका नामों के साथ ActiveRecord क्वेरी

scope :current, ->(as_at = Time.now) { current_and_expired(as_at).current_and_future(as_at) } 
scope :current_and_future, ->(as_at = Time.now) { where("#{upper_bound_column} IS NULL OR #{upper_bound_column} >= ?", as_at) } 
scope :current_and_expired, ->(as_at = Time.now) { where("#{lower_bound_column} IS NULL OR #{lower_bound_column} <= ?", as_at) } 

def self.lower_bound_column 
    lower_bound_field 
end 
def self.upper_bound_column 
    upper_bound_field 
end 

और has_many के माध्यम से जाना जाता है, उदाहरण के: has_many :company_users, -> { current }

तो एक ActiveRecord क्वेरी जो कुछ मॉडलों के लिए संदर्भित करता जाता है

मेरी चिंताओं में से एक में, मैं इन के समान स्कोप जिसमें चिंता शामिल है, इसका परिणाम 'संदिग्ध कॉलम नाम' अपवाद में होता है जो समझ में आता है।

मदद करने के लिए इस पर काबू पाने, मैं, स्तंभ नाम सहायक विधियों में परिवर्तन अब

def self.lower_bound_column 
    "#{self.table_name}.#{lower_bound_field}" 
end 
def self.upper_bound_column 
    "#{self.table_name}.#{upper_bound_field}" 
end 

कौन सा अच्छा काम करता है होना करने के लिए जब तक आप स्वयं को संदर्भित प्रश्नों की आवश्यकता है। अरेल जिसके परिणामस्वरूप एसक्यूएल में तालिका नाम अलियासिंग से इन मुद्दों को कम, उदाहरण के लिए मदद करता है:

LEFT OUTER JOIN "company_users" "company_users_companies" ON "company_users_companies"."company_id" = "companies"."id"

और

INNER JOIN "company_users" ON "users"."id" = "company_users"."user_id" WHERE "company_users"."company_id" = $2

यहां मुद्दा यह है कि self.table_name अब तालिका नाम का उल्लेख है प्रश्न में और यह गाल संकेत में जीभ में परिणाम: HINT: Perhaps you meant to reference the table alias "company_users_companies"

अरेल के लिए खत्म हो इन प्रश्नों विस्थापित करने की कोशिश में, मैं करने के लिए स्तंभ नाम सहायक तरीकों को बदल दिया:

def self.lower_bound_column 
    self.class.arel_table[lower_bound_field.to_sym] 
end 
def self.upper_bound_column 
    self.class.arel_table[upper_bound_field.to_sym] 
end 

और स्कोप अद्यतन प्रतिबिंबित करने के लिए:

lower_bound_column.eq(nil).or(lower_bound_column.lteq(as_at))

लेकिन यह सिर्फ भर के बाद से self.class.arel_table हमेशा क्वेरी की परवाह किए बिना ही होगा मुद्दा स्थलांतरित किया।

मुझे लगता है कि मेरे सवाल है, है कि कैसे मैं दायरे होते स्वयं को संदर्भित प्रश्नों में इस्तेमाल किया जा सकता है, जो इस तरह के <= और >= के रूप में ऑपरेटरों की आवश्यकता होती है बना सकता हूँ?


संपादित करता

मैं मदद करने के लिए इस मुद्दे का प्रदर्शन एक बुनियादी आवेदन बनाया है।

git clone [email protected]:fattymiller/expirable_test.git 
cd expirable_test 
createdb expirable_test-development 
bundle install 
rake db:migrate 
rake db:seed 
rails s 

निष्कर्ष और मान्यताओं sqlite3 में

  1. काम करता है, नहीं Postgres। सबसे अधिक संभावना है क्योंकि पोस्टग्रेस एसक्यूएल में प्रश्नों के क्रम को लागू करता है?
+0

मुझे एक ही समस्या है। मेरा प्रश्न यहां देखें: http://stackoverflow.com/questions/28595636/rails-4-how-to-give-alias-names-to-includes-and-joins-in-active-record-que – phlegx

उत्तर

9

अच्छा, ठीक है, ठीक है।Arel, ActiveRecord और Rails मुद्दों (ऐसा लगता है कि यह नया नहीं है) के स्रोतों को देखकर काफी बड़ा समय बाद, मैं वर्तमान arel_table ऑब्जेक्ट तक पहुंचने का तरीका ढूंढ सकता था, इसके table_aliases के साथ यदि उनका उपयोग किया जा रहा है, current इसके निष्पादन के पल में दायरा।

यह जानने के लिए संभव है कि JOIN के भीतर स्कोप का उपयोग किया जा रहा है, जिसमें तालिका का नाम अलियाकृत है, या यदि दूसरी तरफ वास्तविक तालिका नाम पर दायरा का उपयोग किया जा सकता है।

मैं सिर्फ अपने Expirable चिंता करने के लिए इस विधि कहा:

def self.current_table_name 
    current_table = current_scope.arel.source.left 

    case current_table 
    when Arel::Table 
    current_table.name 
    when Arel::Nodes::TableAlias 
    current_table.right 
    else 
    fail 
    end 
end 

आप देख सकते हैं, मैं आधार वस्तु के रूप में उपयोग कर रहा हूँ current_scope अरेल तालिका देखने के लिए, self.class.arel_table का उपयोग करने का प्रारंभिक कोशिशों के बजाय या यहां तक ​​कि relation.arel_table, जैसा कि आपने कहा था वैसा ही इस्तेमाल किया गया था, इस पर ध्यान दिए बिना। मैं उस ऑब्जेक्ट पर source को Arel::SelectManager प्राप्त करने के लिए बस बुला रहा हूं जो बदले में आपको #left पर वर्तमान तालिका देगा। इस समय दो विकल्प हैं: आपके पास Arel::Table है (कोई उपनाम नहीं, तालिका का नाम #name पर है) या आपके पास Arel::Nodes::TableAlias है जो इसके #right पर उपनाम के साथ है।

कि TABLE_NAME आप #{current_table_name}.#{lower_bound_field} और #{current_table_name}.#{upper_bound_field} अपने कार्यक्षेत्रों में के अपने पहले ही प्रयास करने के लिए वापस कर सकते हैं

:

def self.lower_bound_column 
    "#{current_table_name}.#{lower_bound_field}" 
end 

def self.upper_bound_column 
    "#{current_table_name}.#{upper_bound_field}" 
end 

scope :current_and_future, ->(as_at = Time.now) { where("#{upper_bound_column} IS NULL OR #{upper_bound_column} >= ?", as_at) } 
scope :current_and_expired, ->(as_at = Time.now) { where("#{lower_bound_column} IS NULL OR #{lower_bound_column} <= ?", as_at) } 

यह current_table_name विधि मुझे लगता है कुछ है कि एआर/अरेल सार्वजनिक पर उपयोगी होगा होना करने के लिए एपीआई, तो इसे संस्करण उन्नयन में बनाए रखा जा सकता है। तुम क्या सोचते हो?

आप रुचि रखते हैं, यहाँ कुछ संदर्भों मैं सड़क के नीचे किया जाता है:

  • एक similar question on SO,, कोड की एक टन के साथ उत्तर दिया कि आप अपने सुंदर और संक्षिप्त की क्षमता के बजाय इस्तेमाल कर सकते हैं।
  • यह Rails issue और यह other one
  • और the commit on your test app गीथब पर जिसने हरे रंग का परीक्षण किया!
+0

धन्यवाद इस मुद्दे के साथ आपकी मदद और प्रयास के लिए बहुत कुछ! मेरे शोध ने बहुत ही समान सुझाव दिखाए - एक भी जेनरेट किए गए एसक्यूएल को पार्स करने का सुझाव देता है: | मुझे लगता है कि एक कारण होगा कि उन्होंने आपके सुझाव के समान कुछ शामिल नहीं किया है, लेकिन रेलवे टीम के साथ यह देखने के लिए निश्चित रूप से एक चर्चा के लायक होगा कि क्या वे आपके समाधान को मूल में विलय करने पर विचार करेंगे - आपका भविष्य के कोडर देखने के लिए नाम कोड के एक बहुत अच्छे हिस्से के खिलाफ होगा .. – fatty

+0

मुझे मदद करने में खुशी है और मैं कह सकता हूं कि मैंने इस के साथ बहुत कुछ सीखा है! काफी चुनौतीपूर्ण :) यदि वे पीआर पर विचार करेंगे तो मैं रेल मुद्दे पर पूछूंगा। धन्यवाद! – dgilperez

संबंधित मुद्दे