Преамбула:
Я исследовал, как создать версию API, и нашел несколько способов сделать это.Я решил попробовать предложение Питера Уильямса и создал новые типы пантомимы вендора, чтобы указать версию и формат.Я не смог найти никакой конкретной записи для того, чтобы сделать это по «рельсовому пути», поэтому я собрал информацию из нескольких мест.Я смог заставить его работать, но есть некоторая глупость в том, как средства визуализации обрабатывают массив виджетов против экземпляра виджета в respond_with
.
Основные шаги и проблема:
Я зарегистрировал типы MIME и добавил средства визуализации для версии 1 в xml и json в ApplicationController, средства визуализации вызывают в модели методы 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)
и дублированием в модели.
Мой вопрос: кто-нибудь делал что-то похожее немного чище?
- = обновленный код = -
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
ОБНОВЛЕНИЕ:
Нашел другое решение, которое чувствует себя лучше, но все же немного странно (мне все еще не совсем комфортно с патчами обезьяны), вероятно, хорошо, хотя... в основном перенес сбор данных ответа из метода класса to_myproj_v1_json
в патч обезьяны на массиве.Таким образом, при наличии массива виджетов он вызывает метод экземпляра as_myproj_v1_json
для каждого виджета и возвращает весь массив в нужном формате.
Одна заметка:
- as_json hasничего не делать с форматом JSON, просто создает хэш.Добавьте пользовательское форматирование в as_myproj_v1_json (или переопределение as_json, если вы не используете пользовательские типы MIME), затем to_json изменит хеш на строку json.
я обновил код ниже, чтобы быть тем, чтоВ настоящее время используется, поэтому оригинальный вопрос может не иметь смысла.если кто-то хочет, чтобы исходный вопрос и код были показаны как было, и исправили код в ответе, я могу сделать это вместо этого.