Улучшенная сериализация JSON в Ruby on Rails - PullRequest
18 голосов
/ 03 марта 2009

Я хочу отобразить индекс всех статей вместе с полной статьей через JSON в моем приложении rails, но у меня возникли небольшие проблемы с выяснением, как это сделать.

Вот мой контроллер сейчас:

if params[:id]
    @article = Article.find(params[:id])
else
    @article = Article.published.not_draft.by_recent.first
end

respond_to do |format|

format.js { render :json => @article.to_json(
:except => [ :created_at, :updated_at, :draft, :id, :publish ], 
:include => {
    :comments => {
        :only => [:body]
    }
}),
:callback => params[:callback]}
end

Что я хотел бы сделать в ответе, так это добавить индекс всех статей, например:

@index = Article.find(:all, :select => 'id, title')

Единственный способ, которым я смог это сделать, - поместить индекс и статью в хеш или массив, а затем поместить это в JSON.

@response = { :item => @article, :index => @index }

Полный код с обоими:

@index = Article.find(:all, :select => 'id, title')

if params[:id]
    @article = Article.find(params[:id])
else
    @article = Article.published.not_draft.by_recent.first
end

@response = { :item => @article, :index => @index }

respond_to do |format|

format.js { render :json => @response.to_json(), :callback => params[:callback]}

end

Это было бы хорошо, за исключением того, что теперь я не могу указать :include или :except и заставить его правильно отображаться.

Ответы [ 7 ]

28 голосов
/ 15 августа 2010

Вы намекаете на решение в вашем вопросе. Скорее всего, вы хотите создать хеш для рендеринга в JSON. Предпочтительный способ сделать это сейчас - предоставить реализацию метода as_json. as_json предоставляет формальные средства для настройки вывода to_json путем создания хеша, содержащего данные, которые вы хотите кодировать.

Более подробное описание взаимодействия as_json и to_json можно найти в блоге Джонатана Джулиана .

2 голосов
/ 04 марта 2009

Для ясности приведенный выше код работает с: include и: кроме. И под работами я подразумеваю, что это не выдает ошибку. Проблема в том, что он включает комментарии для каждой статьи в индексе. Я только хочу включить комментарии для: item, а не какие-либо статьи, перечисленные в индексе.

Мне не удалось заставить вложенность работать как хеш или объект OpenStruct.

Вложение на: include выдает ошибку, вложение на: кроме не выдает ошибку, но ничего не отфильтровывается,: созданный_т и т. Д. Все еще отображаются.

...

@response = { :item => @article, :index => @index }

format.js { render :json => @response.to_json(
:except => {:item => [ :created_at, :updated_at, :draft, :id, :publish ]}, 
:include => { :item => {
        :comments => {
                :only => [:body]
        }
}}),
:callback => params[:callback]}
end
1 голос
/ 28 июня 2011

(Пожалуйста, примите ответ)

Я думаю, что ссылка, которую дал нирвдрум, содержит ваш ответ. Я отвечаю только потому, что никто не упомянул encode_json.

В вашем случае вы должны иметь дело только с as_json. Либо путем создания хэша (с различными вызовами на as_json) и отправки его на render :json => ... (без вызова на to_json), либо путем простого внедрения as_json в вашей модели и позволяя рельсам делать всю работу. (Но я подозреваю, что вам понадобится первое.)

Если вам действительно нужны какие-то необычные js в ответе, то вы можете реализовать encode_json в ваших классах (опять же, не to_json). Например:

class JsEmptyClosure
  def encode_json(*args)
    "jQuery[\"noop\"] || function(){}"
  end
  def as_json(*args) self end
end

Теперь он будет отвечать на to_json с действительным js (но учтите, что на самом деле это не json).

1 голос
/ 10 августа 2010

to_json имеет параметр: method, который включает в себя результат любого метода, который вы назвали, вы можете определить метод для этой модели, который возвращает дополнительные данные, которые вы хотите в своем JSON.

1 голос
/ 03 марта 2009

Вы должны иметь возможность вкладывать :include, :except и т. Д. Примерно так:

:except => {:item => [ :created_at, :updated_at, :draft, :id, :publish ]}...

Если это не сработает, сделайте его объектом (например, OpenStruct) вместо хеша.

- Маркус

0 голосов
/ 10 июля 2012

Я бы порекомендовал перегрузить метод атрибутов для возврата альтернативного хэша, который будет автоматически использоваться в выводе to_json.

class Article
   def attributes
     { ... } # define your hash that you want to return at the '...'
   end
end

Мне кажется, это намного проще, чем копаться напрямую с to_json.

0 голосов
/ 28 июня 2012

Спасибо за вопрос, я могу настроить свой формат json для модели с несколькими ассоциациями.

render json: @ posts.to_json (

: кроме => [: созданный_кат,: обновленный_ат,: идентификатор_пользователя],

: include => {

: пользователь => {: только => [: электронная почта,: телефон]},

: location => {: only => [: title,: lat,: lon,: street,: city,: state, : Почтовый индекс]},

: uploads => {: only => [: image]}

}
)

...