Ruby-объекты и JSON-сериализация (без Rails)

Я пытаюсь понять ландшафт сериализации JSON в Ruby. Я новичок в Руби.

Есть ли хорошие варианты сериализации JSON, если вы не работаете с Rails?

Кажется, именно в этом заключается ответ (на Rails). Как преобразовать объект Ruby в JSON.

Похоже, что с помощью json gem вам нужно написать собственный метод to_json. Я не смог заставить to_json работать с массивами и хэшами (в документации сказано, что он работает с ними). ​​Есть ли причина, по которой гем json не просто отражает объект и использует стратегию сериализации по умолчанию? Разве не так to_yaml работает (догадываясь здесь)

12 ответов

Чтобы библиотека JSON была доступна, вам, возможно, придется установить libjson-ruby от вашего менеджера пакетов.

Чтобы использовать библиотеку 'json':

require 'json'

Чтобы преобразовать объект в JSON (эти 3 способа эквивалентны):

JSON.dump object #returns a JSON string
JSON.generate object #returns a JSON string
object.to_json #returns a JSON string

Чтобы преобразовать текст JSON в объект (эти 2 способа эквивалентны):

JSON.load string #returns an object
JSON.parse string #returns an object

Это будет немного сложнее для объектов из ваших собственных классов. Для следующего класса to_json создаст что-то вроде "\"#<A:0xb76e5728>\"",

class A
    def initialize a=[1,2,3], b='hello'
        @a = a
        @b = b
    end
end

Это, вероятно, не желательно. Чтобы эффективно сериализовать ваш объект как JSON, вы должны создать свой собственный метод to_json. Для этого был бы полезен метод класса from_json. Вы можете расширить свой класс следующим образом:

class A
    def to_json
        {'a' => @a, 'b' => @b}.to_json
    end
    def self.from_json string
        data = JSON.load string
        self.new data['a'], data['b']
    end
end

Вы можете автоматизировать это, унаследовав класс JSONable:

class JSONable
    def to_json
        hash = {}
        self.instance_variables.each do |var|
            hash[var] = self.instance_variable_get var
        end
        hash.to_json
    end
    def from_json! string
        JSON.load(string).each do |var, val|
            self.instance_variable_set var, val
        end
    end
end

Тогда вы можете использовать object.to_json сериализовать в JSON и object.from_json! string скопировать сохраненное состояние, которое было сохранено в виде строки JSON, в объект.

Проверьте Oj. Когда дело доходит до конвертации любого старого объекта в JSON, есть ошибки, но Oj может это сделать.

require 'oj'

class A
    def initialize a=[1,2,3], b='hello'
        @a = a
        @b = b
    end
end

a = A.new
puts Oj::dump a, :indent => 2

Это выводит:

{
  "^o":"A",
  "a":[
    1,
    2,
    3
  ],
 "b":"hello"
}

Обратите внимание, что ^o используется для обозначения класса объекта и используется для десериализации. Опускать ^oиспользовать :compat Режим:

puts Oj::dump a, :indent => 2, :mode => :compat

Выход:

{
  "a":[
    1,
    2,
    3
  ],
  "b":"hello"
}

Если производительность рендеринга критична, вы также можете посмотреть на yajl-ruby, который является привязкой к библиотеке C yajl. API сериализации для этого выглядит так:

require 'yajl'
Yajl::Encoder.encode({"foo" => "bar"}) #=> "{\"foo\":\"bar\"}"

Какую версию Ruby вы используете? ruby -v скажу тебе.

Если это 1.9.2, JSON включен в стандартную библиотеку.

Если ты на 1.8.что то делай gem install json и он установит. Затем в вашем коде сделайте:

require 'rubygems'
require 'json'

Затем добавить to_json на объект, и вы готовы идти:

asdf = {'a' => 'b'} #=> {"a"=>"b"}
asdf.to_json #=> "{"a":"b"}"

Так как я много искал, чтобы сериализовать Ruby Object в json:

require 'json'

class User
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def as_json(options={})
    {
      name: @name,
      age: @age
    }
  end

  def to_json(*options)
    as_json(*options).to_json(*options)
  end
end

user = User.new("Foo Bar", 42)
puts user.to_json #=> {"name":"Foo Bar","age":42}
require 'json'
{"foo" => "bar"}.to_json
# => "{\"foo\":\"bar\"}"

Если вы используете 1.9.2 или выше, вы можете конвертировать хэши и массивы во вложенные объекты JSON, просто используя to_json.

{a: [1,2,3], b: 4}.to_json

В Rails вы можете вызывать to_json для объектов Active Record. Вы можете передать: include и: only параметры для управления выводом:

@user.to_json only: [:name, :email]

Вы также можете вызвать to_json для отношений AR, вот так:

User.order("id DESC").limit(10).to_json

Вам не нужно ничего импортировать, и все работает точно так, как вы надеетесь.

Jbuilder - это жемчужина, созданная сообществом rails. Но он хорошо работает в среде без рельсов и обладает отличным набором функций.

# suppose we have a sample object as below
sampleObj.name #=> foo
sampleObj.last_name #=> bar

# using jbuilder we can convert it to json:
Jbuilder.encode do |json|
  json.name sampleObj.name
  json.last_name sampleObj.last_name
end #=> "{:\"name\" => \"foo\", :\"last_name\" => \"bar\"}"

Чтобы получить сборку в классах (таких как Array и Hash) для поддержки as_json а также to_json, вам нужно require 'json/add/core' (подробности см. в файле readme)

Старый поток, но все еще законный вопрос. Я лично был разочарован параметрами сериализации в ruby, особенно зная, насколько медленным это может быть из-за драгоценных камней, не учитывающих распределение памяти. Я использовал их все эти годы.

Я создал undraper-serializer и использовал его в коммерческих условиях с общедоступными API большого объема с потенциалом возврата 10 МБ JSON. Основные преимущества этого камня:

  • Очень быстро
  • Разрешить выбор полей для возврата (возможность выбора, аналогичная GraphQL)
  • Полууверенный, чтобы контролировать естественное возникновение в больших базах кода, чтобы добавлять и изменять так много, что вывод становится прожорливым
  • HATEOAS, который легко сделать (и необязательно)

На самом деле, существует камень под названием Jsonable, https://github.com/treeder/jsonable. Это довольно мило.

Раньше я virtus, Действительно мощный инструмент, позволяющий создать динамическую структуру структуры Ruby на основе заданных вами классов. Легкий DSL, возможно создание объектов из рубиновых хэшей, есть строгий режим. Проверьте это.

Другие вопросы по тегам