Karma veritabanına kaydetmek için Rails serileştirme kullanma


135

Bir karma eşleme kimliklerini raylar uygulamamdaki birkaç denemeye kaydetmeye çalışıyorum. Bu yeni sütunu barındırmak için veritabanına geçişim:

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

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

Modelimde:

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

Ama bunu yaparak test etmek için raylar konsolunu kullandığımda:

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

Çıktı yanlış. Burada sorun ne?


4
Kaydı kaydetmeye çalıştıktan sonra user.errors dosyasında bir şey var mı?
Martijn

1
Gelecekte, bir istisna oluşturmak ve bir hata mesajı görüntülemek için bang yöntemini (kaydet!) Kullanabilirsiniz.
leishman

En iyi yanıt şimdi bir JSON sütunu kullanıyor stackoverflow.com/a/21397522/1536309
Blair Anderson

Yanıtlar:


174

Sütun türü yanlış. Dize yerine Metin kullanmalısınız. Bu nedenle, taşıma işleminiz şöyle olmalıdır:

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

Sonra Rails sizin için YAML'ye uygun şekilde dönüştürür (ve uygun serileştirmeyi gerçekleştirir). Dize alanlarının boyutu sınırlıdır ve yalnızca özellikle küçük değerleri içerir.


1
@BenjaminBunun arkasındaki neden nedir, neden karma 'string' veri tipinde saklayamıyorum.
Lohith MV

8
Çünkü veritabanında, String 255 sabit uzunluktadır (sanırım). Ancak karşılaştırmalı büyüklükte bir hash serileştirecek olsaydınız, bu kolayca uzunluğu aşacaktır. Diziler için de aynı durum geçerlidir. Metin çok daha büyük uzunluklara izin verir.
Benjamin Tan Wei Hao

72

GÜNCELLENMİŞ:

Tam uygulama veritabanınız bağlıdır, ancak PostgreSQL artık vardır jsonve jsonbdoğal olarak sizin karma / nesne verileri depolamak ve izin verebilir sütunları ActiveRecord ile JSON karşı sorguda !

geçişinizi değiştirin ve işiniz bitti.

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

ORİJİNAL:

Daha fazla detay için: raylar dokümanlar && apidock

Emin sütun olduğundan emin olun :textve:string

Göç:

$ rails g migration add_location_data_to_users location_data:text

oluşturmalı:

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

Sınıfınız şöyle görünecektir:

class User < ActiveRecord::Base
  serialize :location_data
end

Mevcut Eylemler:

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

Daha Müthiş ?!

postgresql hstore kullanın

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

Hstore ile serileştirilmiş alanda özellikleri ayarlayabilirsiniz

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

2
Gerçekten harika! Teşekkürler!
Alexander Gorg

18

Rails 4 adlı yeni bir özellik var Store , böylece probleminizi çözmek için kolayca kullanabilirsiniz. Bunun için bir erişimci tanımlayabilirsiniz ve serileştirilmiş mağaza için kullanılan veritabanı sütununu bir metin olarak bildirmeniz önerilir, bu nedenle bol miktarda yer vardır. Orijinal örnek:

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'
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.