해시 할 Rails 객체


147

다음과 같은 객체가 생성되었습니다.

@post = Post.create(:name => 'test', :post_number => 20, :active => true)

이것이 저장되면 객체를 해시로 되돌릴 수 있기를 원합니다.

@object.to_hash

레일 안에서 어떻게 이런 일이 가능합니까?

답변:


296

속성 만 찾으려면 다음을 통해 속성을 얻을 수 있습니다.

@post.attributes

30
루핑 할 때 이것을 사용하지 마십시오 . 비싼 방법 . as_json와 함께 가십시오
AnkitG

5
.to_json모델이 완료되지 않은 경우 DB를 쿼리합니다
ykhrustalev가

1
함께 작동 joins하고 select, Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributes반환합니다 { street: "", name: "" }
fangxing

3
@AnkitG 나는 as_json이 덜 비싸다고 생각하지 않습니다. 에 대한 소스 코드를 살펴보면을 as_json호출 serializable_hash하여 차례로 호출합니다 attributes! 따라서 귀하의 조언은 실제로 두 층의 복잡성을 추가하여 attributes더 비쌉니다.
sandre89

2
.as_json루비 해시로 객체를 직렬화합니다
roadev

45

가장 최신 버전의 Rails (정확히 알 수는 없음)에서 다음 as_json방법을 사용할 수 있습니다 .

@post = Post.first
hash = @post.as_json
puts hash.pretty_inspect

출력 :

{ 
  :name => "test",
  :post_number => 20,
  :active => true
}

조금 더 나아가려면 다음과 같이하여 속성이 표시되는 방식을 사용자 정의하기 위해 해당 메소드를 대체 할 수 있습니다.

class Post < ActiveRecord::Base
  def as_json(*args)
    {
      :name => "My name is '#{self.name}'",
      :post_number => "Post ##{self.post_number}",
    }
  end
end

그런 다음 위와 동일한 인스턴스를 사용하여 다음을 출력합니다.

{ 
  :name => "My name is 'test'",
  :post_number => "Post #20"
}

이것은 물론 어떤 속성을 표시해야하는지 명시 적으로 지정해야 함을 의미합니다.

도움이 되었기를 바랍니다.

편집하다 :

또한 화석 보석을 확인할 수 있습니다 .


OP는 JSON을 요구하지 않고 해시를 요구했습니다.
David Hempy

5
@DavidHempy downvoting 전에 내 답변을 철저히 읽으십시오. 내 내 예에 나타낸 바와 같이,이 정확히 무엇인지 #as_json 수행하고위한 것입니다 : api.rubyonrails.org/classes/ActiveModel/Serializers/... . 그 방법의 이름을 선택하지 않았습니다.
Raf

25
@object.as_json

as_json은 모델 관계에 따라 복잡한 객체를 구성하는 매우 유연한 방법을 가지고 있습니다.

모델 캠페인상점에 속하며 하나의 목록이 있습니다.

모델 목록 에는 많은 list_tasks가 있고 각 list_tasks 에는 많은 주석 .

모든 데이터를 쉽게 결합하는 하나의 json을 얻을 수 있습니다.

@campaign.as_json(
    {
        except: [:created_at, :updated_at],
        include: {
            shop: {
                except: [:created_at, :updated_at, :customer_id],
                include: {customer: {except: [:created_at, :updated_at]}}},
            list: {
                except: [:created_at, :updated_at, :observation_id],
                include: {
                    list_tasks: {
                        except: [:created_at, :updated_at],
                        include: {comments: {except: [:created_at, :updated_at]}}
                    }
                }
            },
        },
        methods: :tags
    })

공지 방법 : : tags 는 다른 객체와 관련이없는 추가 객체를 첨부하는 데 도움이됩니다. 모델 campaign에 이름 태그 가 있는 메소드를 정의하기 만하면 됩니다. 이 메소드는 필요한 것을 반환해야합니다 (예 : Tags.all)

as_json 공식 문서


이것을 찾기 직전에 커스텀 함수를 만들었습니다. 클래스의 함수를 정의하는 대신 더 많은 일회용 메소드를 원했습니다. 어떤 이유로 XML 직렬화 메소드를 사용한 후에도이를 놓쳤습니다. to_변형은 거의 정확히 같은 작동하는 것 같다 as_, 변형 인용 출력을 제외하고. 내가 싫어하는 유일한 것은 필터 기준의 순서를 유지하지 않는 것입니다. 알파벳순으로 정렬 된 것 같습니다. 나는 그것이 내 환경에있는 awesome_print 보석과 관련이 있다고 생각했지만 그것이 사실이라고 생각하지 않습니다.
Pysis

8

다음 중 하나를 사용하여 해시로 반환 된 모델 객체의 속성을 가져올 수 있습니다.

@post.attributes

또는

@post.as_json

as_json연관 및 속성을 포함하고 포함 / 제외 할 속성을 지정할 수 있습니다 ( 문서 참조 ). 그러나 기본 객체의 속성 만 필요한 경우 루비 2.2.3 및 레일 4.2.2를 사용하여 내 앱에서 벤치마킹 attributes하면 시간이 절반보다 적게 걸립니다 as_json.

>> p = Problem.last
 Problem Load (0.5ms)  SELECT  "problems".* FROM "problems"  ORDER BY "problems"."id" DESC LIMIT 1
=> #<Problem id: 137, enabled: true, created_at: "2016-02-19 11:20:28", updated_at: "2016-02-26 07:47:34"> 
>>
>> p.attributes
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> p.as_json
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> n = 1000000
>> Benchmark.bmbm do |x|
?>   x.report("attributes") { n.times { p.attributes } }
?>   x.report("as_json")    { n.times { p.as_json } }
>> end
Rehearsal ----------------------------------------------
attributes   6.910000   0.020000   6.930000 (  7.078699)
as_json     14.810000   0.160000  14.970000 ( 15.253316)
------------------------------------ total: 21.900000sec

             user     system      total        real
attributes   6.820000   0.010000   6.830000 (  7.004783)
as_json     14.990000   0.050000  15.040000 ( 15.352894)

join metho로 중첩 된 리소스를 실행하는 경우 as_json이 데이터베이스 쿼리를 다시 호출합니다.
Tony Hsieh

6

여기에 좋은 제안이 있습니다.

ActiveRecord 모델을 해시로 취급 할 수 있다는 점에 주목할 가치가 있다고 생각합니다.

@customer = Customer.new( name: "John Jacob" )
@customer.name    # => "John Jacob"
@customer[:name]  # => "John Jacob"
@customer['name'] # => "John Jacob"

따라서 속성의 해시를 생성하는 대신 객체 자체를 해시로 사용할 수 있습니다.


6

속성을 사용하여 모든 속성을 반환 할 수는 있지만 인스턴스 메서드를 Post에 추가하고 "to_hash"라고 부르고 해시에서 원하는 데이터를 반환하도록 할 수 있습니다. 같은 것

def to_hash
 { name: self.name, active: true }
end

2

그것이 필요한지 확실하지 않지만 루비 콘솔에서 이것을 시도하십시오 :

h = Hash.new
h["name"] = "test"
h["post_number"] = 20
h["active"] = true
h

분명히 콘솔에서 해시를 반환합니다. 메소드 내에서 해시를 리턴하려면- "h"대신 "return h.inspect"를 사용하십시오.

def wordcount(str)
  h = Hash.new()
  str.split.each do |key|
    if h[key] == nil
      h[key] = 1
    else
      h[key] = h[key] + 1
    end
  end
  return h.inspect
end

포스터는 Rails의 ActiveRecord 모델에 대해 묻습니다.
Jeffrey Harrington

2

내 해결책 :

Hash[ post.attributes.map{ |a| [a, post[a]] } ]

0

Swanand의 답변은 훌륭합니다.

FactoryGirl을 사용하는 경우 해당 build메소드를 사용 하여 키없이 속성 해시를 생성 할 수 있습니다 id. 예 :

build(:post).attributes

0

오래된 질문이지만 많이 참조 ... 나는 대부분의 사람들이 다른 방법을 사용한다고 생각하지만 실제로 to_hash방법이 있으므로 올바르게 설정해야합니다. 일반적으로 pluck은 레일 4 이후에 더 나은 대답입니다 ...이 스레드 또는 유용한 것을 찾기 위해 무리를 검색하고 다른 사람들이 동일한 문제를 겪고 있다고 가정하기 때문에 주로 대답합니다 ...

참고 : 모든 사람에게 권장하지는 않지만 가장 중요한 경우입니다!


루비 온 레일즈 API에서 ... http : //api.rubyonrails.org/classes/ActiveRecord/Result.html ...

This class encapsulates a result returned from calling #exec_query on any database connection adapter. For example:

result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
result # => #<ActiveRecord::Result:0xdeadbeef>

...

# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
      {"id" => 2, "title" => "title_2", "body" => "body_2"},
      ...
     ] ...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.