Преамбула:
Я исследовал версию API и нашел несколько способов сделать это. Я решил попробовать предложение peter williams и создал новые типы mime поставщика, чтобы указать версию и формат. Я не мог найти окончательной записи для этого, следуя "пути рельсов", поэтому я собрал информацию из нескольких мест. Я смог заставить его работать, но есть некоторая глупость в том, как рендереры обрабатывают массив Widget vs Widget в respond_with
.
Основные шаги и проблемы:
Я зарегистрировал типы mime и добавил рендереры для версии 1 как в xml, так и в json для ApplicationController, методы рендеринга call to_myproj_v1_xml
и to_myproj_v1_json
в модели. respond_with(@widget)
работает отлично, но respond_with(@widgets)
выбрасывает HTTP/1.1 500 Internal Server Error
, говоря, что "Шаблон отсутствует".
Временное решение:
"Шаблон отсутствует" означает, что рендер не был вызван и не существует подходящего шаблона. случайно, я обнаружил, что он ищет метод класса... поэтому я придумал код, ниже которого работает, но я не очень доволен им. Глупость в основном связана и связана с xml = obj.to_myproj_v1_xml(obj)
и дублированием в модели.
Мой вопрос: кто-нибудь сделал что-то подобное в несколько более чистом виде?
- = обновленный код = -
конфиг/Инициализаторы/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
приложение/контроллеры/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
приложение/модели/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
приложение/контроллеры/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
конфигурации/инициализаторы/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
UPDATE:
Нашел еще одно решение, которое чувствует себя лучше, но все еще немного странно (мне все еще не совсем удобно с патчами обезьян), возможно, нормально, хотя... в основном перемещало построение данных ответа из метода класса to_myproj_v1_json
на патч обезьяны на массиве. Таким образом, когда есть массив виджетов, он вызывает метод экземпляра as_myproj_v1_json
для каждого виджета и возвращает весь массив в нужном формате.
Одно примечание:
- as_json не имеет ничего общего с json-форматом, просто создает хэш. Добавьте настраиваемое форматирование в as_myproj_v1_json (или переопределение as_json, если вы не используете пользовательские типы mime), тогда to_json изменит хэш на строку json.
Я обновил код ниже, чтобы быть тем, что в настоящее время используется, поэтому исходный вопрос может не иметь смысла. если кто-то захочет исходный вопрос и код, показанный как есть, и фиксированный код в ответе, я могу это сделать.