177 votes

Rails Object to hash

J'ai l'objet suivant qui a été créé

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

Une fois que l'objet est sauvegardé, je veux être capable de le récupérer dans un hash, par exemple en faisant quelque chose du genre :

@object.to_hash

Comment cela est-il possible à partir de rails ?

343voto

Swanand Points 6576

Si vous ne recherchez que des attributs, vous pouvez les obtenir en cliquant ici :

@post.attributes

Notez que cela appelle ActiveModel::AttributeSet.to_hash à chaque fois que vous l'invoquez, donc si vous devez accéder au hachage plusieurs fois, vous devez le mettre en cache dans une variable locale :

attribs = @post.attributes

34 votes

Ne l'utilisez pas pour les boucles, Méthode coûteuse . Aller avec as_json

8 votes

.to_json interrogera la base de données si le modèle n'est pas complet

1 votes

Fonctionne avec joins y select , Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributes , reviendra { street: "", name: "" }

53voto

Raf Points 359

Dans la version la plus récente de Rails (je ne peux pas dire laquelle exactement), vous pouviez utiliser la fonction as_json méthode :

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

Rendement :

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

Pour aller un peu plus loin, vous pouvez remplacer cette méthode afin de personnaliser la façon dont vos attributs apparaissent, en faisant quelque chose comme ceci :

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

Ensuite, avec la même instance que ci-dessus, on obtiendra :

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

Cela signifie bien sûr que vous devez spécifier explicitement les attributs qui doivent apparaître.

J'espère que cela vous aidera.

EDIT :

Vous pouvez également vérifier le Hashifiable gemme.

0 votes

L'OP n'a pas demandé du JSON, mais un hash.

7 votes

@DavidHempy S'il vous plaît, lisez attentivement ma réponse avant de faire un vote négatif. Comme je l'ai montré dans mes exemples, c'est exactement ce que fait #as_json et ce à quoi il est destiné : api.rubyonrails.org/classes/ActiveModel/Serializers/ . Je n'ai pas choisi le nom de cette méthode.

0 votes

Merci, vous m'avez sauvé la vie.

26voto

Serge Seletskyy Points 1859
@object.as_json

as_json a une manière très flexible de configurer un objet complexe selon les relations du modèle.

EXEMPLE

Modèle campagne appartient à boutique et a un liste

Modèle liste a de nombreux liste_tâches et chacun de liste_tâches a de nombreux commentaires

Nous pouvons obtenir un json qui combine toutes ces données facilement.

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

Avis méthodes : :tags peut vous aider à attacher tout objet supplémentaire qui n'a pas de relations avec les autres. Il suffit de définir une méthode avec le nom tags en modèle campagne . Cette méthode devrait retourner ce dont vous avez besoin (par exemple Tags.all).

Documentation officielle pour as_json

0 votes

J'avais créé une fonction personnalisée juste avant de trouver ceci. Je voulais plutôt une méthode à usage unique, plutôt que de définir une fonction pour la classe. Cela m'a échappé même après avoir travaillé avec les méthodes de sérialisation XML pour une raison quelconque. Le site to_ semble fonctionner presque exactement de la même manière que la variante as_ variante, sauf pour la sortie citée. La seule chose que je n'ai pas aimée, c'est que l'ordre de mes critères de filtrage n'a pas été préservé. Il semble qu'ils soient triés par ordre alphabétique. Je pensais que cela était lié à la gemme awesome_print que j'ai dans mon environnement, mais je ne pense pas que ce soit le cas.

6voto

Jeff Points 952

Il y a d'excellentes suggestions ici.

Je pense qu'il est utile de noter que vous pouvez traiter un modèle ActiveRecord comme un hash comme ceci :

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

Par conséquent, au lieu de générer un hachage des attributs, vous pouvez utiliser l'objet lui-même comme un hachage.

6voto

Curtis Edmond Points 169

Vous pourriez certainement utiliser les attributs pour renvoyer tous les attributs, mais vous pourriez ajouter une méthode d'instance à Post, l'appeler "to_hash" et lui faire renvoyer les données que vous souhaitez dans un hachage. Quelque chose comme

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X