ハッシュするRailsオブジェクト


147

作成した次のオブジェクトがあります

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

これを保存したら、オブジェクトをハッシュに戻すことができるようにしたいと思います。たとえば、次のような処理を行います。

@object.to_hash

これはレール内からどのようにして可能ですか?

回答:


295

属性のみを探している場合は、次の方法で取得できます。

@post.attributes

30
ループするときにこれを使用しないでください、高価な方法。as_jsonで行く
AnkitG 2013

5
.to_jsonモデルが完全でない場合、DBにクエリを実行します
ykhrustalev 2016年

1
連携joinsしてselectPerson.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributes返します { street: "", name: "" }
fangxing

3
@AnkitG as_jsonの方が安いとは思いません。のソースコードを見るとas_json、それが呼び出さserializable_hashれ、次にattributes!したがって、あなたのアドバイスは、実際にに2層の複雑さを追加attributesすることであり、さらに高価になります。
sandre89 2018

2
.as_jsonオブジェクトをrubyハッシュにシリアル化します
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反対票を投じる前に私の回答をよく読んでください。私の例で示したように、これは#as_jsonが行うこととまったく同じであり、api.rubyonrails.org / classes / ActiveModel / Serializers / …を対象としています。その方法の名前は選びませんでした。
Raf

25
@object.as_json

as_jsonには、モデルの関係に従って複雑なオブジェクトを構成する非常に柔軟な方法があります

モデルキャンペーンショップに属し、1つありますリストます

モデルリストには多くのlist_tasksがあり、各list_tasksには多くのコメントます

これらすべてのデータを簡単に組み合わせる1つの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は、他のオブジェクトと関係のない追加のオブジェクトを添付するのに役立ちます。モデルキャンペーンで名前タグを使用してメソッドを定義するだけです。このメソッドは必要なものをすべて返す必要があります(例:Tags.all)

as_jsonの公式ドキュメント


これを見つける直前にカスタム関数を作成していました。クラスの関数を定義するのではなく、使い捨てのメソッドをもっと必要としていました。何らかの理由でXMLシリアル化メソッドを操作した後でも、これを逃しました。to_バリアントは、ほぼ正確に同じ動作しているようですas_引用された出力を除いて、バリアントを。私が気に入らなかった唯一のことは、フィルター基準の順序を維持しなかったことです。アルファベット順にソートされているようです。私の環境にあるawesome_print gemに関連していると思いましたが、そうではないと思います。
Pysis 2018

8

次のいずれかを使用して、ハッシュとして返されたモデルオブジェクトの属性を取得できます。

@post.attributes

または

@post.as_json

as_json関連付けとその属性を含めたり、どの属性を含めたり除外したりするかを指定したりできます(ドキュメントを参照)。ただし、ベースオブジェクトの属性のみが必要な場合、Ruby 2.2.3とRails 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

それが必要なものかどうかはわかりませんが、rubyコンソールでこれを試してください:

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、


0

スワナンドの答えは素晴らしいです。

FactoryGirlを使用している場合は、そのbuildメソッドを使用して、キーなしで属性ハッシュを生成できますid。例えば

build(:post).attributes

0

古い質問ですが、頻繁に参照されています...ほとんどの人は他の方法を使用していると思いますが、実際には方法があり、正しくto_hash設定する必要があります。一般的に、pluckはrails 4の後でより良い答えです...主にこれを答えるのは、このスレッドまたは有用な何かを見つけるために束を検索しなければならなかったためです。

注:これはすべての人に推奨されているわけではありませんが、特別なケースです!


Ruby on Rails 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.