2010-01-17 7 views
54

kullanarak serialize? çok daha uygun Raylar> = 3.1 cevabını aşağıdaActiveRecord Ben tefrika sütunu kullanan bir modele sahip JSON yerine YAML

+0

Bazı "sihirli" veya eklenti olacağını umuyorum, ama çözüm oldukça düz ileri ve çok güzel çalışıyor. –

+0

toby, kabul edilen cevabı buna göre değiştirebilir misiniz? http://stackoverflow.com/a/6971678/190135 http://meta.stackexchange.com/questions/120568/is-it-possible-to-change-the-chosen-answer – AlexChaffee

cevap

155

yapabilirsiniz sadece

Ben varsayılan alır kendi YAML kodlayıcı yazdı
+1

Bence bunun nedeni: [: dump,: load] .all {| s | :: JSON.respond_to? s} ', sadece varsayılan 'YAMLColumn' gibi yapar. Bir denetleyicide, 'JSON == :: JSON' ve' JSON! = :: ActiveSupport :: JSON'. –

+1

Bu Rails 3.2.1 ile çalıştı, ancak 3.2.2 ile durdu: https://github.com/rails/rails/issues/5797 bakın Umarım bu çok uygun olduğu için sabitlenir! – gmcnaughton

+2

3.2.5 –

11

Güncelleme

Bkz ortalarında en yüksek puanlı yanıt. Bu Rails < 3.1 için mükemmel bir cevaptır.

Muhtemelen aradığınız şey budur. Model geri aramalar ekleyin

gem install json 

2) oluştur JsonWrapper sınıf

# lib/json_wrapper.rb 

require 'json' 
class JsonWrapper 
    def initialize(attribute) 
    @attribute = attribute.to_s 
    end 

    def before_save(record) 
    record.send("#{@attribute}=", JsonWrapper.encrypt(record.send("#{@attribute}"))) 
    end 

    def after_save(record) 
    record.send("#{@attribute}=", JsonWrapper.decrypt(record.send("#{@attribute}"))) 
    end 

    def self.encrypt(value) 
    value.to_json 
    end 

    def self.decrypt(value) 
    JSON.parse(value) rescue value 
    end 
end 

3):

Form.find(:first).to_json 

Güncelleme

1) 'json' gem yükleyin

#app/models/user.rb 

class User < ActiveRecord::Base 
    before_save  JsonWrapper.new(:name) 
    after_save  JsonWrapper.new(:name) 

    def after_find 
     self.name = JsonWrapper.decrypt self.name 
    end 
end 

4) Test edin!

User.create :name => {"a"=>"b", "c"=>["d", "e"]} 

PS:

Oldukça KURU değil, ama ben elimden geleni yaptım. Herkes User modelinde after_find'u düzeltebilirse harika olur. Sonunda

require "json/ext" 

    before_save :json_serialize 
    after_save :json_deserialize 


    def json_serialize  
    self.options = self.options.to_json 
    end 

    def json_deserialize  
    self.options = JSON.parse(options) 
    end 

    def after_find 
    json_deserialize   
    end 

Alkış, oldukça kolay:

+1

adresine bakın. . O ister: Seçenekler özniteliği, jml verisine serileştirilecek, yaml'ye değil. – Eimantas

+0

Ja, serialize kullanarak, seçenekler alanındaki değerler veritabanında YAML-serialized değeri olarak saklanır. Bunun yerine JSON olmasını istiyorum. –

+0

Cevabı güncellendi. –

8

Benim gereksinimleri yani benim distile kod yukarıdaki cevabı bir çeşidi, bu aşamada kod yeniden kullanımı çok gerek yoktu!

+0

Bu yalnızca belirli veri türleriyle çalışacaktır. Örneğin 'input = 'foo'; serialized = input.to_json; JSON.parse (serialized) ' # => JSON :: ParserError: 757: /Users/username/.rbenv/versions/2.2.2/lib/ruby/gems/2.2 adresinden" foo "'daki beklenmedik belirteci .0/gems/json-1.8.3/lib/json/common.rb: 155: 'parse' https://makandracards.com/makandra/15611-how-to-fix-unexpected-token-error -for-json-parse Bunun için iyi bir geçici çözüm, Ruby's Marshal kütüphanesini kullanmaktır. JSON veya YAML'den daha hızlı ve güvenilirdir. –

1

Daha basit bir çözüm, this blog post by Michael Rykov'da açıklandığı gibi composed_of kullanmaktır. Bu çözümü çok beğendim çünkü daha az geri arama kullanılmasını gerektiriyor.

composed_of :settings, :class_name => 'Settings', :mapping => %w(settings to_json), 
         :constructor => Settings.method(:from_json), 
         :converter => Settings.method(:from_json) 

after_validation do |u| 
    u.settings = u.settings if u.settings.dirty? # Force to serialize 
end 
+0

Ne yazık ki, corporate_of kullanımdan kaldırılmıştır. http://blog.plataformatec.com.br/2012/06/about-the-composed_of-removal/ bunun yerine özel bir serializer kullanılmasını önerir. –

0

Aleran, Rails 3 ile bu yöntemi kullandık: Burada

bu özü nedir? Biraz da aynı sorunu yaşadım ve bu yazıya Michael Rykov tarafından girdiğimde serileştirilmeye doğru ilerliyordum, ancak blogunda yorum yapmak mümkün değil ya da en azından bu yazıyla ilgili. Anladığım kadarıyla, Ayarlar sınıfını tanımlamanıza gerek olmadığını söylüyor, ancak bunu denediğimde, Ayarın tanımlanmadığını bana anlatmaya devam ediyor. Öyleyse sadece onu kullanıp kullanmadığınızı ve daha ne anlatılmalı? Teşekkürler.

+0

Elbette Ayar sınıfına ihtiyacınız var. Ama muhtemelen doğrudan JSON sınıfında çalışabilirsiniz. : constructor => JSON.yöntem (: ayrıştırma),: dönüştürücü => JSON.method (: ayrıştırma),: eşleme =>% w (my_attribute to_json). Yine de denemedim. – balu

58

Rails 3.1'de serialize numaralı özel kodlayıcıları kullanabilirsiniz.

class ColorCoder 
    # Called to deserialize data to ruby object. 
    def load(data) 
    end 

    # Called to convert from ruby object to serialized data. 
    def dump(obj) 
    end 
end 

class Fruits < ActiveRecord::Base 
    serialize :color, ColorCoder.new 
end 

Bu yardımcı olur umarım.

Referanslar:

Tanımı serialize ait: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L556

varsayılan YAML kodlayıcı rayları gemilere: load çağrısı https://github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/yaml_column.rb

Ve bu olur: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L132

+1

Rails'e dahil edilmemiş olmasına rağmen, yazım sırasında, buradaki Rails'e bir JSONColumn Coder katkıda bulundu: https://gist.github.com/txus/rails/blob/1a2ce8e56c4313a7466c2b0b08a037e44d033f6c/activerecord/lib/active_record/coders /json_column.rb - çekme isteği ayrıntıları burada: https://gist.github.com/rails/rails/pull/196. Umarım bu, serialize + JSON kullanmak isteyen herkes yardımcı olur. –

3

serialize :attr, JSON 0 kullanıyoryöntem şöyle çalışır: url json ve kimlik denetimi kullanılmıyorsa Serileştirilecek niteliktir

composed_of :auth, 
       :class_name => 'ActiveSupport::JSON', 
       :mapping => %w(url to_json), 
       :constructor => Proc.new { |url| ActiveSupport::JSON.decode(url) } 

url özniteliği için json formatında değerini kaydeder modeline uygun yeni bir yöntemdir. (Tam olarak test ancak çalışıyor gibi görünüyor değil) Rails 3.1

3

yardımcı
class Form < ActiveRecord::Base 
    serialize :column, JSON 
end 

Umut. Burada sınıf: örnek yöntemler modelin tanımı serialize ikinci argüman olarak geçirilecek bir örneği gerektirir olan

class JSONColumn 
    def initialize(default={}) 
    @default = default 
    end 

    # this might be the database default and we should plan for empty strings or nils 
    def load(s) 
    s.present? ? JSON.load(s) : @default.clone 
    end 

    # this should only be nil or an object that serializes to JSON (like a hash or array) 
    def dump(o) 
    JSON.dump(o || @default) 
    end 
end 

load yana ve dump. İşte bunun bir örnek:

class Person < ActiveRecord::Base 
    validate :name, :pets, :presence => true 
    serialize :pets, JSONColumn.new([]) 
end 

Ben, yeni bir örneğini oluşturarak örneği yüklenirken ve lRB bir örneğini damping çalıştı ve hepsi düzgün çalışması gibiydi. Ben de bu konuda bir blog post yazdım.

+0

olmalıdır Rails için gerçekten yeniyim. JSONColumn sınıfını nereye koyayım? Nereye ekleyebilirim? Teşekkürler! –

+0

Bunu yapmanın pek çok yolu var, ama burada bir yol var: 'lib/json_column.rb' içine koyabilir ve' 'json_column''unu' config/environment.rb''ye ekleyebilirsiniz. –

+0

Bunun için teşekkürler. Varsayılan bir değer ayarlayabileceğinize sevindim. Bunu bir set (sırasız dizi) gibi davranan bir sütun oluşturmak için kullandım: serileştirme: bir şey, JsonSerializer.new (Set.new) –

İlgili konular