web-dev-qa-db-fra.com

Utilisation de Rails sérialiser pour enregistrer le hachage dans la base de données

J'essaie de sauvegarder un identifiant de mappage de hachage pour un certain nombre de tentatives dans mon Rails. Ma migration vers la base de données pour répondre à cette nouvelle colonne:

class AddMultiWrongToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :multi_wrong, :string
  end

  def self.down
    remove_column :users, :multi_wrong
  end
end

Dans mon modèle j'ai:

class User < ActiveRecord::Base 
 serialize :multi_wrong, Hash
end

Mais lorsque j’utilise la console Rails) pour tester cela, procédez comme suit:

user = User.create()
user.multi_wrong = {"test"=>"123"}
user.save

La sortie est fausse. Qu'est-ce qui ne va pas ici?

133
cmwright

Le type de colonne est incorrect. Vous devriez utiliser Text au lieu de String. Par conséquent, votre migration devrait être:

 def self.up
   add_column :users, :multi_wrong, :text
 end

Alors Rails le convertira correctement en YAML pour vous (et effectuera la sérialisation appropriée). Les champs de chaînes de caractères ont une taille limitée et ne contiendront que des valeurs particulièrement petites.

172

UPDATED:

L'implémentation exacte dépendra de votre base de données, mais PostgreSQL dispose maintenant des colonnes json et jsonb qui peuvent stocker de manière native vos données de hachage/objet et vous permettent de interroger le JSON avec ActiveRecord !

changez votre migration et vous avez terminé.

class Migration0001
  def change
    add_column :users, :location_data, :json, default: {}
  end
end

ORIGINAL:

Pour plus de détails: documentation Rails && apidock

Assurez-vous que votre colonne est :text et pas :string

Migration:

$ Rails g migration add_location_data_to_users location_data:text

devrait créer:

class Migration0001
  def change
    add_column :users, :location_data, :text
  end
end

Votre classe ressemblerait à:

class User < ActiveRecord::Base
  serialize :location_data
end

Actions disponibles:

b = User.new
b.location_data = [1,2,{foot: 3, bart: "noodles"}]
b.save

Plus génial?!

utiliser postgresql hstore

class AddHstore < ActiveRecord::Migration  
  def up
    enable_extension :hstore
  end

  def down
    disable_extension :hstore
  end
end 

class Migration0001
  def change
    add_column :users, :location_data, :hstore
  end
end

Avec hstore, vous pouvez définir des attributs sur le champ sérialisé

class User < ActiveRecord::Base  
  # setup hstore
  store_accessor :location_data, :city, :state
end
66
Blair Anderson

Rails 4 a une nouvelle fonctionnalité appelée Store , de sorte que vous pouvez facilement l'utiliser pour résoudre votre problème. Vous pouvez définir un accesseur pour celui-ci et il est recommandé de déclarer la colonne de base de données utilisée pour le magasin sérialisé sous forme de texte, afin de laisser beaucoup d'espace. L'exemple original:

class User < ActiveRecord::Base
  store :settings, accessors: [ :color, :homepage ], coder: JSON
end

u = User.new(color: 'black', homepage: '37signals.com')
u.color                          # Accessor stored attribute
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor

# There is no difference between strings and symbols for accessing custom attributes
u.settings[:country]  # => 'Denmark'
u.settings['country'] # => 'Denmark'
17
Aboozar Rajabi