Rails Object to hash


147

Saya memiliki objek berikut yang telah dibuat

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

Setelah ini disimpan, saya ingin dapat mengembalikan objek ke hash, misalnya dengan melakukan sesuatu seperti:

@object.to_hash

Bagaimana ini mungkin dari dalam rel?

Jawaban:


296

Jika Anda hanya mencari atribut, maka Anda bisa mendapatkannya dengan:

@post.attributes

30
Jangan gunakan ini saat perulangan, metode Mahal . Pergilah dengan as_json
AnkitG

5
.to_jsonakan meminta DB jika model tidak lengkap
ykhrustalev

1
Bekerja dengan joinsdan select,, Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributesakan kembali { street: "", name: "" }
fangxing

3
@AnkitG Saya tidak percaya as_json lebih murah. Jika Anda melihat kode sumber untuk as_json, itu akan memanggil serializable_hashyang, pada gilirannya, akan memanggil attributes! Jadi saran Anda sebenarnya menambahkan dua lapisan kompleksitas attributes, menjadikannya lebih mahal.
sandre89

2
.as_jsonakan membuat serial objek menjadi ruby ​​hash
roadev

45

Di versi Rails terbaru (tidak tahu yang mana tepatnya), Anda bisa menggunakan as_jsonmetode ini:

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

Akan menghasilkan:

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

Untuk melangkah lebih jauh, Anda bisa mengganti metode itu untuk menyesuaikan cara atribut Anda muncul, dengan melakukan sesuatu seperti ini:

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

Kemudian, dengan contoh yang sama seperti di atas, akan menampilkan:

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

Ini tentu saja berarti Anda harus secara eksplisit menentukan atribut mana yang harus ditampilkan.

Semoga ini membantu.

EDIT:

Anda juga dapat memeriksa permata Hashifiable .


OP tidak meminta JSON, tetapi untuk hash.
David Hempy

5
@ DavidHempy Harap baca jawaban saya dengan seksama sebelum downvoting. Seperti yang saya tunjukkan dalam contoh saya, inilah yang dilakukan #as_json dan dimaksudkan untuk: api.rubyonrails.org/classes/ActiveModel/Serializers/… . Saya tidak memilih nama metode itu.
Raf

25
@object.as_json

as_json memiliki cara yang sangat fleksibel untuk mengkonfigurasi objek kompleks sesuai dengan hubungan model

CONTOH

Kampanye model milik toko dan memiliki satu daftar

Daftar model memiliki banyak list_tasks dan masing-masing list_tasks memiliki banyak komentar

Kita bisa mendapatkan satu json yang menggabungkan semua data itu dengan mudah.

@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
    })

Metode pemberitahuan :: tag dapat membantu Anda melampirkan objek tambahan yang tidak memiliki hubungan dengan orang lain. Anda hanya perlu mendefinisikan metode dengan tag nama dalam kampanye model . Metode ini harus mengembalikan apa pun yang Anda butuhkan (mis. Tags.all)

Dokumentasi resmi untuk as_json


Telah membuat fungsi kustom sebelum menemukan ini. Ingin lebih dari metode sekali pakai, daripada mendefinisikan fungsi untuk kelas. Kehilangan ini bahkan setelah bekerja dengan metode serialisasi XML untuk beberapa alasan. The to_varian tampaknya bekerja hampir persis sama dengan as_varian, kecuali untuk output dikutip. Satu-satunya hal yang saya tidak suka adalah tidak menjaga urutan kriteria filter saya. Tampaknya diurutkan berdasarkan abjad. Saya pikir itu terkait dengan permata awesome_print yang saya miliki di lingkungan saya, tapi saya tidak berpikir itu masalahnya.
Pysis

8

Anda bisa mendapatkan atribut dari objek model yang dikembalikan sebagai hash menggunakan salah satu

@post.attributes

atau

@post.as_json

as_jsonmemungkinkan Anda untuk menyertakan asosiasi dan atributnya serta menentukan atribut mana yang akan disertakan / dikecualikan (lihat dokumentasi ). Namun, jika Anda hanya memerlukan atribut objek dasar, pembandingan di aplikasi saya dengan ruby ​​2.2.3 dan rail 4.2.2 menunjukkan bahwa attributesmembutuhkan waktu kurang dari setengah waktu 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)

as_json akan memanggil kueri basis data lagi, jika Anda menjalankan sumber bersarang dengan bergabung dengan metho
Tony Hsieh

6

Ada beberapa saran bagus di sini.

Saya pikir perlu dicatat bahwa Anda dapat memperlakukan model ActiveRecord sebagai hash seperti:

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

Oleh karena itu, alih-alih menghasilkan hash atribut, Anda dapat menggunakan objek itu sendiri sebagai hash.


6

Anda pasti bisa menggunakan atribut untuk mengembalikan semua atribut tetapi Anda bisa menambahkan metode instance ke Posting, sebut saja "to_hash" dan minta itu mengembalikan data yang Anda inginkan dalam hash. Sesuatu seperti

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

2

tidak yakin apakah itu yang Anda butuhkan tetapi coba ini di konsol ruby:

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

jelas itu akan mengembalikan Anda hash di konsol. jika Anda ingin mengembalikan hash dari dalam metode - alih-alih hanya "h" coba gunakan "return h.inspect", sesuatu yang mirip dengan:

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

Poster bertanya tentang model ActiveRecord di Rails.
Jeffrey Harrington

2

Solusi saya:

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

0

Jawaban Swanand luar biasa.

jika Anda menggunakan FactoryGirl, Anda bisa menggunakan buildmetode untuk menghasilkan hash atribut tanpa kunci id. misalnya

build(:post).attributes

0

Pertanyaan lama, tetapi sangat direferensikan ... Saya pikir kebanyakan orang menggunakan metode lain, tetapi ada fakta to_hash metode yang benar, itu harus diatur dengan benar. Secara umum, pemetik adalah jawaban yang lebih baik setelah rail 4 ... menjawab ini terutama karena saya harus mencari banyak untuk menemukan utas ini atau apa pun yang berguna & dengan asumsi orang lain memukul masalah yang sama ...

Catatan: tidak merekomendasikan ini untuk semua orang, tetapi kasus tepi!


Dari batu ruby ​​on rails ... 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"},
      ...
     ] ...
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.