Ответ 1
Для ответа: см. вопрос: -)
Короче говоря, существуют разные решения, из которых один находится в вопросе выше:
- Monkey-patch Array для реализации метода, который даст (старый) v1 JSON обратно
Преамбула:
Я исследовал версию 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
для каждого виджета и возвращает весь массив в нужном формате.
Одно примечание:
Я обновил код ниже, чтобы быть тем, что в настоящее время используется, поэтому исходный вопрос может не иметь смысла. если кто-то захочет исходный вопрос и код, показанный как есть, и фиксированный код в ответе, я могу это сделать.
Для ответа: см. вопрос: -)
Короче говоря, существуют разные решения, из которых один находится в вопросе выше:
Я не видел этого трюка типа контента, используемого где-либо в проекте Rails, прежде чем это стало новым для меня. Как я обычно видел, это определение пространства имен маршрутов (например,/api/v1/), которое идет на контроллер (скажем, Api:: Version1Controller).
Кроме того, я знаю, что вы хотите делать вещи "Rails way", и, может быть, это звучит как crotchety, исходящий от парня, который был с Rails с версии 1.3, но весь материал respond_with
/respond_to
довольно мал меня. Я не знал, что respond_to
ищет метод to_XXX
, когда он сериализует объекты, например (возможно, мне нужно прочитать об этом). Имеющеся в такой же манере, как кажется, довольно глупо. Кроме того, для API форматирование данных модели - это действительно работа вида, а не модель. В этом случае я мог бы рассмотреть что-то вроде rabl. Там хорошая запись об этом здесь.