rails 3 формат ответа и управление версиями с использованием типа MIME поставщика в заголовке Accept

Преамбула:

Я исследовал, как сделать версию API, и нашел несколько способов сделать это. Я решил попробовать предложение Питера Уильямса и создал новые типы MIME для определения версии и формата. Я не смог найти исчерпывающего описания того, что делал это по «рельсовому пути», поэтому я собрал информацию из нескольких мест. Мне удалось заставить его работать, но есть некоторая глупость в том, как рендереры обрабатывают массив виджетов и экземпляр виджета в response_with .

Основные шаги и проблема:

Я зарегистрировал типы mime и добавил рендереры для версии 1 как в xml, так и в json в ApplicationController, рендереры вызывают методы to_myproj_v1_xml и to_myproj_v1_json в модели. response_with (@widget) работает нормально, но response_with (@widgets) вызывает HTTP / 1. 1 500 Внутренняя ошибка сервера : «Шаблон отсутствует».

Временное решение:

«Шаблон отсутствует» означает, что визуализация не вызывалась и соответствующий шаблон не существует. случайно я обнаружил, что он ищет метод класса ... поэтому я придумал приведенный ниже код, который работает, но я не очень доволен им. Глупость в основном связана с xml = obj.to_myproj_v1_xml (obj) и дублированием в модели.

У меня вопрос - делал ли кто-нибудь что-нибудь похожее чуть более чистым способом?

- = обновленный код = -

config / initializers / mime_types.rb :

Mime::Type.register 'application/vnd.com.mydomain.myproj-v1+xml', :myproj_v1_xml
Mime::Type.register 'application/vnd.com.mydomain.myproj-v1+json', :myproj_v1_json

app / controllers / application_controller. rb :

class ApplicationController < ActionController::Base
  protect_from_forgery
  before_filter :authenticate

  ActionController.add_renderer :myproj_v1_xml do |obj, options|
    xml = obj.to_myproj_v1_xml
    self.content_type ||= Mime::Type.lookup('application/vnd.com.mydomain.myproj-v1+xml')
    self.response_body = xml
  end

  ActionController.add_renderer :myproj_v1_json do |obj, options|
    json = obj.to_myproj_v1_json
    self.content_type ||= Mime::Type.lookup('application/vnd.com.mydomain.myproj-v1+json')
    self.response_body  = json
  end
end

app / models / widget.rb :

class Widget < ActiveRecord::Base
  belongs_to :user
  V1_FIELDS = [:version, :model, :description, :name, :id]

  def to_myproj_v1_xml
    self.to_xml(:only => V1_FIELDS)
  end

  def to_myproj_v1_json
    self.to_json(:only => V1_FIELDS)
  end

  def as_myproj_v1_json
    self.as_json(:only => V1_FIELDS)
  end
end

app / controllers / widgets_controller.rb :

class WidgetsController < ApplicationController

  respond_to :myproj_v1_xml, :myproj_v1_json

  def index
    @widgets = @user.widgets
    respond_with(@widgets)
  end

  def create
    @widget = @user.widgets.create(params[:widget])
    respond_with(@widget)
  end

  def destroy
    @widget = @user.widgets.find(params[:id])
    respond_with(@widget.destroy)
  end

  def show
    respond_with(@widget = @user.widgets.find(params[:id]))
  end

...

end

config / initializers / monkey_array.rb

class Array

  def to_myproj_v1_json(options = {})
    a = []
    self.each { |obj| a.push obj.as_myproj_v1_json }
    a.to_json()
  end

  def to_myproj_v1_xml(options = {})
    a = []
    self.each { |obj| a.push obj.as_myproj_v1_json } # yes this is json instead of xml.  as_json returns a hash
    a.to_xml()
  end

end

ОБНОВЛЕНИЕ:

Нашел другое решение, которое выглядит лучше, но все же немного странно (я все еще не совсем уверен в патчах обезьяны), хотя, вероятно, нормально ... в основном переместил сборку данных ответа из метода класса в_myproj_v1_json к патчу обезьяны на Array. Таким образом, когда есть массив виджетов, он вызывает метод экземпляра as_myproj_v1_json для каждого виджета и возвращает весь массив в желаемом формате.

Одно примечание:

  • as_json не имеет ничего общего с json формат, просто создает хеш. Добавьте настраиваемое форматирование в as_myproj_v1_json (или переопределение as_json, если вы не используете настраиваемые типы mime), тогда to_json изменит хэш на строку json.

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

25
задан Jack B Nimble 19 August 2011 в 18:36
поделиться