Rails as_json issue - Как эффективно включить вложенные объекты?

У меня возникает проблема, когда я работаю с методом as_json и как эффективно возвращать объект в JSON. И он принадлежит объекту как JSON, а объект принадлежит этому объекту принадлежит свой object_to. Код, вероятно, объяснит это лучше.

Нерабочий путь

Класс предупреждения

class Alert < ActiveRecord::Base
    belongs_to :message
    # for json rendering
    def as_json(options={})
        super(:include => :message)
    end
end

Класс сообщений

 def as_json(options={})
    super( methods: [:timestamp, :num_photos, :first_photo_url, :tag_names],
           include: { camera: { only: [:id, :name] },
                      position: { only: [:id, :name, :address, :default_threat_level ]},
                      images: { only: [:id, :photo_url, :is_hidden]} })
  end

Проблема с этой первой настройкой заключается в том, что когда у меня есть объект Alert и вызывается

alert.as_json()

Я получаю все атрибуты из Alert и всех атрибутов из Message, но ни один из других атрибутов из сообщения, которое я хочу, например Camera, Position и т.д.

Здесь "Это работает, но, вероятно, не правильный путь дизайна"

Класс предупреждения

class Alert < ActiveRecord::Base

    belongs_to :message

    # for json rendering
    def as_json(options={})
        super().merge(:message => message.as_json)
    end
end

Класс сообщений

  # for json rendering
  def as_json(options={})
    super( methods: [:timestamp, :num_photos, :first_photo_url, :tag_names])
          .merge(:camera => camera.as_json)
          .merge(:position => position.as_json)
          .merge(:images => images.as_json)
  end

В этой 2-й настройке я получаю все вложенные атрибуты сообщений, как я хочу.

Мой вопрос: я пропустил какую-то Rails-конвенцию, чтобы сделать это правильно? Похоже, что было бы/должно быть проще.

Ответ 1

Какую версию Rails вы используете? Это известная ошибка в старых версиях Rails, предположительно фиксированная с помощью этого запроса на перенос. Ваш синтаксис подходит ко мне, поэтому, возможно, это ваша проблема?

Кроме того, вы можете также проверить новый active_model_serializers от Jose Valim (основной элемент Rails). Это может по крайней мере дать вам возможность более эффективно обходить вашу проблему.

Ответ 2

Лучший ответ для меня - использование serializable_hash. @kikito коснулся этого в своем комментарии, но была опечатка, которая помешала ему работать. Это не serialized_hash, it serializable_hash.

Буквально просто найдите + замените as_json на serializable_hash, и эта ошибка исчезнет. (Он до сих пор не исправлен в Rails 4.0.2). Вы также получаете преимущество в том, что вам легче выполнять API XML позже (некоторые люди все еще используют их!).

Ответ 3

Я бы порекомендовал вам взглянуть на RABL (означает Ruby API Builder Language) gem (railscast, github). Он предлагает вам DSL для определения структуры вашего ответа JSON (а также XML) в шаблонах (например, Haml или CoffeeScript). Он также поддерживает частичные операции.