2012-06-13 2 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 

, 나는 다음과 같은 얻을

여기서 id는 마지막 s3_image의 ID입니다. select_rows가 예상대로 작동 한 유일한 것입니다.

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

위의 행에 대한 필드 이름을 가져와야합니다. 이 포스팅은

액티브는 방법은 여러 개체를 만들고 가입 (fetch_fields 더 이상 How do you get the rows and the columns in the result of a query with ActiveRecord? 존재하지 않는 것) 내가 원하는 가까이 얻을 수 있지만, 오래된 보인다. 나는 같은 결과를 얻으려고 노력하고 있는데, "포함한다"는 리턴 하겠지만 왼쪽으로 결합한다.

내가 많은 결과 (때로는 전체 테이블)를 반환하려고 시도하고 있기 때문에 이것이 내 요구 사항에 맞지 않는 이유입니다.

+1

다음을 사용하여 ActiveRecord 모델의 모든 열을 가져올 수 있습니다. ** Model.columns.map (& : name) **, 그러나 이것이 원하는지 확실하지 않습니다. – MurifoX

+0

조인을 수행 할 때 어떤 값이 어떤 모델에 속해 있는지 알 수 없습니다. 이것이 필자가 열 이름을 원했던 이유입니다. – Abdo

답변

54

AR이 그냥 방법으로 활성 레코드의 검사 방법은 작동입니다

+6

앞으로 올 사람에게는이 방법이 더 이상 사용되지 않습니다. http://apidock.com/rails/ActiveRecord/Base/column_names/class – pahnin

+0

공유 해 주셔서 감사합니다. @pahnin; 당신이나 다른 사람이 대안을 추천 할 수 있다면 좋을 것입니다. – Abdo

+16

column_names()는 여전히 ActiveRecord 클래스에서 사용 가능하며 다른 모듈로 옮겨졌습니다. – nocache

4

열 이름의 배열을 반환하는 #column_names 방법을 제공합니다 : 그것은 단지 모델의 테이블에서 열의를 보여줍니다.

record.blah 

가 다른 테이블에서 경우에도 ㅋ 속성을 반환하지만 속성은 여전히 ​​존재한다.

record.attributes 

을 사용하여 모든 특성이 포함 된 해시를 얻을 수도 있습니다.

그러나 동일한 이름을 가진 열이 여러 개있는 경우 (예 : 두 테이블 모두에 ID 열이있는 경우) 활성 레코드는 테이블 이름을 무시하고 함께 항목을 함께 처리합니다. 고유하게 만들기 위해 별칭을 지정해야합니다 .

+0

답장을 보내 주셔서 감사합니다. 나는 앨리어싱을 시도했지만 AR에서 다른 것을 얻지 못했습니다. 그것은 항상 같은 결과를 함께 부숴 있습니다. AR이 예상하는 특정 앨리어싱이 있습니까? – Abdo

+0

각 열 이름은 고유해야합니다 (예 : table1. *, table2.id를 t2_id, table2.name을 t2_name 등으로 선택하십시오. AR은 그와 똑똑한 것을하지는 않지만 모든 충돌을 막을 것입니다. –

+0

이것은 모든 단일 열의 별명을 지정해야한다는 것을 의미합니다. 매우 지루한 :-( – Abdo

0

좋아요. 저는 오랫동안 더 효율적으로 뭔가를하고 싶었습니다.

매우 적은 결과 만 포함해도 제대로 작동합니다. 다음과 같은 코드는 참여하고자하는 항목이 많을 때 더 효과적입니다.

코드를 더 쉽게 이해할 수 있도록 먼저 손쉬운 버전을 만든 다음 확장했습니다.

첫 번째 방법 : 다음 우리는 테이블 (N × M 개의 관계)

merge_through "을 통해"할 수 있습니다 것으로 나타났습니다

# 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 

!주소이 문제는 :

여기
# 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의 사용을 만드는) 전체 방법에 대해 지금

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

:

# 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"]