2012-06-13 15 views
30

के साथ कॉलम नाम प्राप्त करें क्या ActiveRecord के साथ वास्तविक कॉलम नाम प्राप्त करने का कोई तरीका है?ActiveRecord

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

#<Location id: 22, name: ... 
> 
:

select locations.*, s3_images.* from locations left join s3_images on s3_images.imageable_id = locations.id and s3_images.imageable_type = 'Location' limit 1 

उपरोक्त उदाहरण में, मैं निम्नलिखित मिल

जहां आईडी अंतिम s3_image है।

Model.connection.select_rows("SELECT id,name FROM users") => [["1","amy"],["2","bob"],["3","cam"]] 

मैं ऊपर दी गई पंक्तियों के लिए फ़ील्ड नाम प्राप्त करने की आवश्यकता: select_rows केवल बात यह है कि उम्मीद के रूप में काम करता है। यह पोस्ट जो चाहता है उसके करीब आता है लेकिन पुराना दिखता है (fetch_fields अब How do you get the rows and the columns in the result of a query with ActiveRecord?)

ActiveRecord जुड़ने की विधि एकाधिक ऑब्जेक्ट्स बनाता है। मैं एक ही परिणाम प्राप्त करने की कोशिश कर रहा हूं "शामिल है" वापस आ जाएगा लेकिन बाएं शामिल होने के साथ।

मैं पूरी तरह से परिणाम (और कभी-कभी पूरी टेबल) वापस करने का प्रयास कर रहा हूं, यही कारण है कि मेरी ज़रूरतों के अनुरूप नहीं है।

+1

आप का उपयोग करके ActiveRecord मॉडल के सभी कॉलम प्राप्त कर सकते हैं: ** Model.columns.map (&: name) **, लेकिन मुझे यकीन नहीं है कि यह वही है जो आप चाहते हैं। – MurifoX

+0

जब मैं शामिल होता हूं, तो मुझे नहीं पता कि कौन से मूल्य मॉडल के हैं। यही कारण है कि मैं कॉलम के नाम चाहता था। भविष्य में यहां आने वाले किसी भी व्यक्ति के लिए – Abdo

उत्तर

54

एआर एक #column_names विधि है कि स्तंभ नाम की एक सरणी

+6

, इस विधि को बहिष्कृत किया गया है http://apidock.com/rails/ActiveRecord/Base/column_names/class – pahnin

+0

साझा करने के लिए धन्यवाद, @pahnin; यह अच्छा होगा अगर आप (या कोई और) विकल्प – Abdo

+16

कॉलम_नाम() अभी भी ActiveRecord कक्षाओं के लिए उपलब्ध है, तो इसे अभी एक अलग मॉड्यूल में स्थानांतरित कर दिया गया है। – nocache

4

यह अभी जिस तरह सक्रिय रिकॉर्ड का निरीक्षण विधि काम करता है देता है प्रदान करता है: यह केवल मॉडल की मेज से स्तंभ के सूचीबद्ध करता है। गुण अभी भी हैं हालांकि

record.blah 

ब्लैह विशेषता वापस कर देगा, भले ही यह किसी अन्य तालिका से हो। आप

record.attributes 

सभी विशेषताओं के साथ हैश प्राप्त करने के लिए भी उपयोग कर सकते हैं।

हालांकि, यदि आपके पास एक ही नाम के साथ कई कॉलम हैं (उदाहरण के लिए दोनों टेबलों में एक आईडी कॉलम है) तो सक्रिय रिकॉर्ड केवल टेबल नाम को अनदेखा कर चीजों को एक साथ जोड़ता है। आपको कॉलम नामों को अद्वितीय बनाने के लिए उन्हें उपनाम करना होगा ।

+0

आपके उत्तर के लिए धन्यवाद। मैंने अलियासिंग करने की कोशिश की लेकिन एआर में कुछ भी अलग नहीं मिला। यह हमेशा एक ही मैश किए हुए परिणामों के साथ मैश किए जाते हैं। क्या एआर उम्मीद करता है कि कोई विशिष्ट अलियासिंग है? – Abdo

+0

प्रत्येक कॉलम नाम को अद्वितीय होना आवश्यक है, उदा। table1। *, table2.id t2_id के रूप में, table2.name t2_name आदि के रूप में। एआर इसके साथ कुछ भी चालाक नहीं करेगा लेकिन यह –

+0

को टकराते हुए सब कुछ रोक देगा इसका मतलब है कि मुझे हर एक डुप्लिकेट कॉलम को उपनाम करना होगा ... बहुत कठिन :-( – Abdo

0

ठीक है मैं कुछ ऐसा करना चाहता हूं जो थोड़ी देर के लिए अधिक कुशल हो।

कृपया ध्यान दें कि बहुत कम परिणामों के लिए, काम ठीक है। नीचे दिया गया कोड बेहतर काम करता है जब आपके पास बहुत सारे कॉलम शामिल होते हैं जिन्हें आप शामिल करना चाहते हैं।

कोड को समझना आसान बनाने के लिए, मैंने पहले एक आसान संस्करण तैयार किया और उस पर विस्तार किया।

सबसे पहले विधि:

# takes a main array of ActiveRecord::Base objects 
# converts it into a hash with the key being that object's id method call 
# loop through the second array (arr) 
# and call lamb (a lambda { |hash, itm|) for each item in it. Gets called on the main 
# hash and each itm in the second array 
# i.e: You have Users who have multiple Pets 
# You can call merge(User.all, Pet.all, lambda { |hash, pet| hash[pet.owner_id].pets << pet } 
def merge(mainarray, arr, lamb) 
    hash = {} 
    mainarray.each do |i| 
     hash[i.id] = i.dup 
    end 

    arr.each do |i| 
     lamb.call(i, hash) 
    end 

    return hash.values 
    end 

मैं तो देखा हम तालिकाओं (nxm रिश्ते)

merge_through "के माध्यम से" हो सकता है!पतों इस मुद्दे:

lambmerge = lambda do |lhash, rhash, lid, rid| 
         lhash[lid].keywords << rhash[rid] 
       end 
    Location.merge_through!(Location.all, Keyword.all, LocationsKeyword.all, lambmerge) 

पूरा विधि के लिए अब

# merges multiple arrays (or hashes) with the main array (or hash) 
    # each arr in the arrs is a hash, each must have 
    # a :value and a :proc 
    # the procs will be called on values and main hash 
    # 
    # :middletable will merge through the middle table if provided 
    # :value will contain the right table when :middletable is provided 
    # 
    def merge_multi!(mainarray, arrs) 
    hash = {} 

    if (mainarray.class == Hash) 
     hash = mainarray 
    elsif (mainarray.class == Array) 
     mainarray.each do |i| 
     hash[i.id] = i.dup 
     end 
    end 

    arrs.each do |h| 
     arr = h[:value] 
     proc = h[:proc] 

     if (h[:middletable]) 
     middletable = h[:middletable] 
     merge_through!(hash, arr, middletable, proc) 
     else 
     arr.each do |i| 
      proc.call(i, hash) 
     end 
     end 
    end 

    return hash.values 
    end 

यहाँ कैसे मैं अपने कोड का उपयोग करें (जो merge_through का उपयोग करता है):

# this works for tables that have the equivalent of 
    # :through => 
    # an example would be a location with keywords 
    # through locations_keywords 
    # 
    # the middletable should should return as id an array of the left and right ids 
    # the left table is the main table 
    # the lambda fn should store in the lefthash the value from the righthash 
    # 
    # if an array is passed instead of a lefthash or a righthash, they'll be conveniently converted 
    def merge_through!(lefthash, righthash, middletable, lamb) 
    if (lefthash.class == Array) 
     lhash = {} 
     lefthash.each do |i| 
     lhash[i.id] = i.dup 
     end 

     lefthash = lhash 
    end 

    if (righthash.class == Array) 
     rhash = {} 
     righthash.each do |i| 
     rhash[i.id] = i.dup 
     end 

     righthash = rhash 
    end 

    middletable.each do |i| 
     lamb.call(lefthash, righthash, i.id[0], i.id[1]) 
    end 

    return lefthash 
    end 

यह कैसे मैं इसे कहते है :

def merge_multi_test() 

    merge_multi!(Location.all, 
       [ 
        # each one location has many s3_images (one to many) 
        { :value => S3Image.all, 
         :proc => lambda do |img, hash| 
          if (img.imageable_type == 'Location') 
          hash[img.imageable_id].s3_images << img 
          end 
         end 
        }, 

        # each location has many LocationsKeywords. Keywords is the right table and LocationsKeyword is the middletable. 
        # (many to many) 
        { :value => Keyword.all, 
         :middletable => LocationsKeyword.all, 
         :proc => lambda do |lhash, rhash, lid, rid| 
         lhash[lid].keywords << rhash[rid] 
         end 
        } 
       ]) 
    end 

आप कर सकते हैं कोड को संशोधित करें यदि आप आलसी लोड गुणों की इच्छा करना चाहते हैं जो कई लोगों में से एक हैं (जैसे कोई शहर किसी स्थान पर है) असल में, उपरोक्त कोड काम नहीं करेगा क्योंकि आपको मुख्य हैश के माध्यम से लूप करना होगा और शहर को सेट करना होगा दूसरा हैश (कोई "city_id, location_id" तालिका नहीं है)। शहर के हश में सभी स्थानों को वापस निकालने के लिए आप शहर और स्थान को उलट सकते हैं। मुझे लगता है कि कोड अभी तक तो मैं यह छोड़ दिया की जरूरत नहीं है =)

10

दो विकल्प

Model.column_names 

या

Model.columns.map(&:name) 
कॉलम नाम, आयु, साथ

उदाहरण मॉडल नामित खरगोश on_facebook

Rabbit.column_names 
Rabbit.columns.map(&:name) 

रिटर्न

["id", "name", "age", "on_facebook", "created_at", "updated_at"]