Rails Nesne hash


152

Oluşturulan aşağıdaki nesneye sahibim

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

Bu kaydedildikten sonra, örneğin şunun gibi bir şey yaparak nesneyi bir hash haline getirebilmek istiyorum:

@object.to_hash

Rayların içinden bu nasıl mümkün olabilir?

Yanıtlar:


301

Yalnızca öznitelikler arıyorsanız, bunları şu şekilde alabilirsiniz:

@post.attributes

ActiveModel::AttributeSet.to_hashHer çalıştırdığınızda bunun çağrıldığını unutmayın, bu nedenle karmaya birden çok kez erişmeniz gerekirse, yerel bir değişkende önbelleğe almalısınız:

attribs = @post.attributes

30
Bunu döngü yaparken kullanmayın, Pahalı yöntem . As_json ile git
AnkitG

6
.to_jsonmodel tamamlanmadıysa
DB'yi sorgulayacak

1
İle çalışır joinsve select, Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributes, dönecektir { street: "", name: "" }
fangxing

4
@AnkitG As_json'un daha ucuz olduğuna inanmıyorum. Kaynak koduna bakarsanız, sırayla as_jsonarayacak serializable_hasholanı arayacak attributes! Yani tavsiyeniz aslında iki kat karmaşıklık ekleyerek attributesonu daha da pahalı hale getiriyor.
sandre89

2
.as_jsonnesneyi ruby ​​hash olarak seri hale getirecek
roadev

47

Rails'in en son sürümünde (hangisi tam olarak bilinemiyor), şu as_jsonyöntemi kullanabilirsiniz :

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

Çıktı:

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

Biraz daha ileri gitmek için, aşağıdaki gibi bir şey yaparak niteliklerinizin görünme şeklini özelleştirmek için bu yöntemi geçersiz kılabilirsiniz:

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

Ardından, yukarıdakiyle aynı örnekle çıktı:

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

Bu, elbette, hangi özelliklerin görünmesi gerektiğini açıkça belirtmeniz gerektiği anlamına gelir.

Bu yardımcı olur umarım.

DÜZENLE :

Ayrıca Hashifiable mücevherini de kontrol edebilirsiniz .


OP, JSON istemedi, ancak bir karma.
David Hempy

6
@DavidHempy Lütfen olumsuz oy kullanmadan önce cevabımı iyice okuyun. Örneklerimde gösterdiğim gibi, bu tam olarak #as_json'un yaptığı şeydir ve api.rubyonrails.org/classes/ActiveModel/Serializers/… . O yöntemin adını ben seçmedim.
Raf

25
@object.as_json

as_json, karmaşık nesneyi model ilişkilerine göre yapılandırmak için çok esnek bir yola sahiptir.

MİSAL

Model kampanyası mağazaya aittir ve tek listeli

Model listesinde birçok list_tasks vardır ve her list_tasks'ın birçok yorumu vardır

Tüm bu verileri kolayca birleştiren bir json alabiliriz.

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

Dikkat yöntemleri:: etiketler , başkalarıyla ilişkisi olmayan herhangi bir ek nesneyi eklemenize yardımcı olabilir. Model kampanyasında ad etiketleriyle bir yöntem tanımlamanız yeterlidir . Bu yöntem, ihtiyacınız olanı döndürmelidir (örneğin, Tags.all)

As_json için resmi belgeler


Bunu bulmadan hemen önce özel bir işlev yapmıştı. Sınıf için bir işlev tanımlamak yerine daha çok tek kullanımlık bir yöntem istiyordu. Bazı nedenlerle XML serileştirme yöntemleriyle çalıştıktan sonra bile bunu kaçırdım. to_Varyant neredeyse tam olarak aynı iş gibi görünüyor as_, varyant alıntılanan çıkış için hariç. Sevmediğim tek şey, filtre kriterlerimin sırasını korumak değildi. Alfabetik olarak sıralanmış görünüyor. Bunun çevremde sahip olduğum awesome_print cevheri ile ilgili olduğunu düşündüm, ama durumun bu olduğunu sanmıyorum.
Pysis

8

Aşağıdakilerden birini kullanarak karma olarak döndürülen bir model nesnesinin niteliklerini alabilirsiniz.

@post.attributes

veya

@post.as_json

as_jsonilişkilendirmeleri ve özniteliklerini eklemenize ve hangi özniteliklerin dahil edileceğini / hariç tutulacağını belirlemenize olanak tanır ( belgelere bakın ). Bununla birlikte, yalnızca temel nesnenin özelliklerine ihtiyacınız varsa, uygulamamda Ruby 2.2.3 ve raylar 4.2.2 ile kıyaslama yapmak, bunun attributesyarısından daha az zaman gerektirdiğini gösterir 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)

katılma yöntemi ile iç içe geçmiş kaynak çalıştırıyorsanız, as_json veritabanı sorgusunu tekrar arayacaktır
Tony Hsieh

6

Burada bazı harika öneriler var.

Bir ActiveRecord modelini şöyle bir hash olarak ele alabileceğinizi belirtmekte fayda var:

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

Bu nedenle, özniteliklerin bir karmasını oluşturmak yerine nesnenin kendisini bir karma olarak kullanabilirsiniz.


6

Öznitelikleri tüm öznitelikleri döndürmek için kesinlikle kullanabilirsiniz, ancak Post'a bir örnek yöntemi ekleyebilir, onu "to_hash" olarak adlandırabilir ve bir karma olarak istediğiniz verileri döndürmesini sağlayabilirsiniz. Gibi bir şey

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

2

ihtiyacın olup olmadığından emin değilim ama bunu Ruby konsolunda dene:

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

belli ki size konsolda bir hash döndürecektir. bir yöntemin içinden bir hash döndürmek istiyorsanız - sadece "h" yerine "return h.inspect" kullanmayı deneyin, buna benzer bir şey:

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, Rails'teki ActiveRecord modellerini soruyor.
Jeffrey Harrington

2

Çözümüm:

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

0

Swanand'ın cevabı harika.

FactoryGirl kullanıyorsanız, anahtarsız buildöznitelik karmasını oluşturmak için yöntemini kullanabilirsiniz id. Örneğin

build(:post).attributes

0

Eski soru, ama yoğun bir şekilde atıfta bulunuluyor ... Sanırım çoğu insan başka yöntemler kullanıyor, ancak aslında bir to_hashyöntem var, doğru ayarlanması gerekiyor. Genel olarak, yolma, raylardan sonra daha iyi bir cevaptır 4 ... temel olarak bu konuyu veya yararlı bir şeyi bulmak için bir grup aramak zorunda kaldım ve başkalarının da aynı soruna çarptığını varsayarsak ...

Not: Bunu herkese tavsiye etmiyoruz, ancak uç durumlar!


Ruby on rails api'den ... 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"},
      ...
     ] ...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.