Schienen Objekt gegen Hash


147

Ich habe das folgende Objekt, das erstellt wurde

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

Sobald dies gespeichert ist, möchte ich in der Lage sein, das Objekt wieder in einen Hash zu versetzen, z. B. indem ich Folgendes tue:

@object.to_hash

Wie ist das innerhalb von Schienen möglich?

Antworten:


294

Wenn Sie nur nach Attributen suchen, können Sie diese erhalten durch:

@post.attributes

30
Verwenden Sie dies nicht beim Schleifen, teure Methode . Gehen Sie mit as_json
AnkitG

5
.to_jsonwird DB abfragen, wenn das Modell nicht vollständig ist
ykhrustalev

1
Arbeitet mit joinsund select, Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributeswird zurückkehren { street: "", name: "" }
Fangxing

3
@AnkitG Ich glaube nicht, dass as_json weniger teuer ist. Wenn Sie sich den Quellcode ansehen as_json, wird er aufrufen serializable_hash, der wiederum aufruft attributes! Ihr Rat ist also, zwei Komplexitätsebenen hinzuzufügen attributes, was es noch teurer macht.
Sandre89

2
.as_jsonwird das Objekt zu Ruby Hash serialisieren
Roadev

45

In der neuesten Version von Rails (kann jedoch nicht genau sagen, welche) können Sie die folgende as_jsonMethode verwenden:

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

Wird ausgegeben:

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

Um noch ein bisschen weiter zu gehen, können Sie diese Methode überschreiben, um die Darstellung Ihrer Attribute anzupassen, indem Sie Folgendes tun:

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

Dann wird mit derselben Instanz wie oben Folgendes ausgegeben:

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

Dies bedeutet natürlich, dass Sie explizit angeben müssen, welche Attribute angezeigt werden müssen.

Hoffe das hilft.

EDIT:

Sie können auch den Hash- Edelstein überprüfen .


OP hat nicht nach JSON gefragt, sondern nach einem Hash.
David Hempy

5
@ DavidHempy Bitte lies meine Antwort gründlich durch, bevor du abstimmst. Wie in meinen Beispielen gezeigt, ist dies genau das, was #as_json tut und für Folgendes bestimmt ist: api.rubyonrails.org/classes/ActiveModel/Serializers/… . Ich habe den Namen dieser Methode nicht gewählt.
Raf

25
@object.as_json

as_json bietet eine sehr flexible Möglichkeit, komplexe Objekte gemäß Modellbeziehungen zu konfigurieren

BEISPIEL

Modell Kampagne gehört zu Geschäft und hat eine Liste

Modell - Liste hat viele list_tasks und jeder von list_tasks hat viele Kommentare

Wir können einen JSON bekommen, der all diese Daten leicht kombiniert.

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

Hinweismethoden :: Mithilfe von Tags können Sie zusätzliche Objekte anhängen, die keine Beziehung zu anderen haben. Sie müssen nur eine Methode mit Namen definieren Tags in Modell - Kampagne . Diese Methode sollte alles zurückgeben, was Sie benötigen (z. B. Tags.all).

Offizielle Dokumentation für as_json


Hatte kurz vor dem Finden eine benutzerdefinierte Funktion erstellt. Wollte eher eine Einwegmethode, als eine Funktion für die Klasse zu definieren. Verpasste dies auch nach der Arbeit mit den XML-Serialisierungsmethoden aus irgendeinem Grund. Die to_Variante scheint as_bis auf die angegebene Ausgabe fast genauso zu funktionieren wie die Variante. Das einzige, was mir nicht gefallen hat, war, die Reihenfolge meiner Filterkriterien nicht beizubehalten. Es scheint alphabetisch sortiert zu sein. Ich dachte, das hängt mit dem Juwel awesome_print zusammen, das ich in meiner Umgebung habe, aber ich glaube nicht, dass dies der Fall ist.
Pysis

8

Sie können die Attribute eines Modellobjekts entweder als Hash zurückgeben

@post.attributes

oder

@post.as_json

as_jsonMit dieser Option können Sie Zuordnungen und deren Attribute einschließen sowie angeben, welche Attribute ein- / ausgeschlossen werden sollen (siehe Dokumentation ). Wenn Sie jedoch nur die Attribute des Basisobjekts benötigen, zeigt das Benchmarking in meiner App mit Ruby 2.2.3 und Rails 4.2.2, dass dies attributesweniger als die Hälfte der Zeit erfordert 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 ruft die Datenbankabfrage erneut auf, wenn Sie eine verschachtelte Ressource mit Join Metho ausführen
Tony Hsieh

6

Hier gibt es einige großartige Vorschläge.

Ich denke, es ist erwähnenswert, dass Sie ein ActiveRecord-Modell wie folgt als Hash behandeln können:

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

Anstatt einen Hash der Attribute zu generieren, können Sie daher das Objekt selbst als Hash verwenden.


6

Sie können die Attribute definitiv verwenden, um alle Attribute zurückzugeben, aber Sie können Post eine Instanzmethode hinzufügen, sie "to_hash" nennen und die gewünschten Daten in einem Hash zurückgeben lassen. Etwas wie

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

2

Ich bin mir nicht sicher, ob du das brauchst, aber versuche es in der Ruby-Konsole:

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

Offensichtlich wird es Ihnen einen Hash in der Konsole zurückgeben. Wenn Sie einen Hash innerhalb einer Methode zurückgeben möchten, verwenden Sie statt "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

Poster fragt nach ActiveRecord-Modellen in Rails.
Jeffrey Harrington

2

Meine Lösung:

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

0

Swanands Antwort ist großartig.

Wenn Sie FactoryGirl verwenden, können Sie die buildMethode verwenden, um den Attribut-Hash ohne den Schlüssel zu generieren id. z.B

build(:post).attributes

0

Alte Frage, aber stark referenziert ... Ich denke, die meisten Leute verwenden andere Methoden, aber es gibt tatsächlich eine to_hashMethode, die richtig eingerichtet werden muss. Im Allgemeinen ist das Zupfen nach Schienen 4 eine bessere Antwort. Dies zu beantworten, hauptsächlich, weil ich einen Haufen durchsuchen musste, um diesen Thread oder irgendetwas Nützliches zu finden und davon auszugehen, dass andere das gleiche Problem haben ...

Hinweis: Dies wird nicht für alle empfohlen, sondern für Randfälle!


Aus dem Rubin auf Schienen 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"},
      ...
     ] ...
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.