2012-04-27 9 views
8

के माध्यम से विशेषता सेटर को मूल्य कैसे भेजें I रेलवे की एसक्यूएल क्वेरी जेनरेट करने से पहले मैं ActiveRecord मॉडल में एक विशेषता सेटर को text2ltree() postgres फ़ंक्शन में अपना मान लपेटने की कोशिश कर रहा हूं।एसक्यूएल फ़ंक्शन

उदाहरण के लिए,

post.path = "1.2.3" 
post.save 

उत्पन्न करनी चाहिए की तरह

UPDATE posts SET PATH=text2ltree('1.2.3') WHERE id = 123 # or whatever 

ऐसा करने का सबसे अच्छा तरीका क्या है कुछ?

+0

आप पोस्टग्रेस फ़ंक्शन (संग्रहीत प्रक्रिया) लिख सकते हैं और फिर बस 'SELECT myfunc (' 1.2.3 ')' कॉल कर सकते हैं। यदि आप उस मार्ग में रूचि रखते हैं तो मैं एक उदाहरण प्रदान कर सकता हूं। –

उत्तर

2

संपादित करें: वास्तव में आप ऊपर के लिए क्या देख रहे प्राप्त करने के लिए, आप अपने मॉडल फ़ाइल में डिफ़ॉल्ट सेटर ओवरराइड करने के लिए इस का उपयोग करेंगे:

def path=(value) 
    self[:path] = connection.execute("SELECT text2ltree('#{value}');")[0][0] 
end 

तो कोड आप ऊपर है काम करता है।

मुझे ActiveRecord के आंतरिक और इसके अभेद्य मेटाप्रोग्रामिंग अंडरपिनिंग के बारे में अधिक जानने में दिलचस्पी है, इसलिए एक अभ्यास के रूप में मैंने नीचे दी गई टिप्पणियों में जो वर्णन किया है उसे पूरा करने का प्रयास किया।

module DatabaseTransformation 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def transformed_by_database(transformed_attributes = {}) 

     transformed_attributes.each do |attr_name, transformation| 

     define_method("#{attr_name}=") do |argument| 
      transformed_value = connection.execute("SELECT #{transformation}('#{argument}');")[0][0] 
      write_attribute(attr_name, transformed_value) 
     end 
     end 
    end 
    end 
end 

class Post < ActiveRecord::Base 
    attr_accessible :name, :path, :version 
    include DatabaseTransformation 
    transformed_by_database :name => "length" 

end 

कंसोल आउटपुट:

1.9.3p194 :001 > p = Post.new(:name => "foo") 
    (0.3ms) SELECT length('foo'); 
=> #<Post id: nil, name: 3, path: nil, version: nil, created_at: nil, updated_at: nil> 

वास्तविक जीवन मुझे लगता है आप include ActiveRecord में मॉड्यूल करना चाहते हैं में यहाँ एक उदाहरण है कि मेरे लिए काम किया (यह सब post.rb में है): : आधार, लोड पथ में कहीं पहले एक फ़ाइल में। आपको डेटाबेस फ़ंक्शन में जो तर्क हो रहा है, उसके प्रकार को सही तरीके से संभालना होगा। आखिरकार, मैंने सीखा कि connection.execute प्रत्येक डेटाबेस एडेप्टर द्वारा कार्यान्वित किया गया है, इसलिए परिणाम का उपयोग करने के तरीके पोस्टग्रेज़ में अलग हो सकते हैं (यह उदाहरण SQLite3 है, जहां परिणाम सेट हैश की सरणी के रूप में वापस किया जाता है और पहले डेटा रिकॉर्ड की कुंजी । 0] है

इस ब्लॉग पोस्ट अविश्वसनीय रूप से मददगार था:

http://www.fakingfantastic.com/2010/09/20/concerning-yourself-with-active-support-concern/

के रूप में था रेल प्लगइन-लेखन के लिए गाइड:

http://guides.rubyonrails.org/plugins.html

इसके अलावा, यह क्या है इसके लिए, मुझे लगता है कि पोस्टग्रेज़ में मैं अभी भी एक प्रश्न पुनर्लेखन नियम बनाने के लिए माइग्रेशन का उपयोग करके ऐसा करूँगा, लेकिन यह एक महान सीखने के अनुभव के लिए बनाया गया है। उम्मीद है कि यह काम करता है और मैं अब यह कैसे करना है इसके बारे में सोचना बंद कर सकता हूं।

+1

ऐसा करने का एक बिल्कुल अलग तरीका है जिसे मैंने अभी सोचा था कि पोस्टग्रेस्क्ल के क्वेरी रीराइट इंजन का उपयोग करना होगा। एक ट्रिगर का उपयोग करने की तरह थोड़ा। आप अपडेट को फिर से लिखने के लिए नियम स्थापित करेंगे जैसे कि फ़ंक्शन के माध्यम से मूल्य पारित किया गया था। उलझन यह है कि आपका मॉडल साफ़ है और आप केवल डेटाबेस में एक कॉल करते हैं। नकारात्मकता यह है कि यह डेटाबेस-अज्ञेयवादी नहीं है, जो स्पष्ट रूप से आपके मामले में कोई मुद्दा नहीं हो सकता है। मैं उदाहरण पोस्ट करने के लिए वाक्यविन्यास के साथ पर्याप्त परिचित नहीं हूं, लेकिन यहां दस्तावेज़ों का एक लिंक है: http://www.postgresql.org/docs/8.4/static/sql-createrule।एचटीएमएल –

+0

मुझे ऐसा लगता है कि ऐसा करने का एक और अधिक प्रभावी तरीका होना चाहिए जिसमें बंदर पैचिंग ActiveRecord/Arel –

+0

शामिल है यदि "कुशल" से आपका प्रदर्शन का मतलब है, क्वेरी फिर से लिखने की विधि बेहतर है; मैं नहीं देखता कि आप रेल में कुछ भी कैसे कार्यान्वित कर सकते हैं जो डीबी को दो कॉल से बचेंगी। यदि "कुशल" से आपका मतलब DRYer/अधिक अभिव्यक्तिपूर्ण है (मान लीजिए कि यह एकमात्र ऐसा स्थान नहीं है जिसे आप कभी भी करना चाहते हैं), तो मैं मानता हूं कि यह एक विकल्प है। –

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