he investigado cómo la versión de una API y encontré varias maneras de hacerlo. Decidí probar la sugerencia peter williams' y crear nuevos tipos de mime de proveedor para especificar la versión y el formato. No pude encontrar ningún escrito definitivo para hacer esto siguiendo "el camino de los rieles", así que reuní información de varios lugares. Pude ponerlo en funcionamiento, pero hay algunos errores en la forma en que los procesadores manejan la matriz de widgets frente a la instancia de widgets en respond_with
.
pasos básicos & de problemas:
I registrados tipos MIME y ha añadido extracción de grasas para la versión 1, tanto en XML y JSON para ApplicationController, los procesadores llaman to_myproj_v1_xml
y to_myproj_v1_json
métodos en el modelo. respond_with(@widget)
funciona bien, pero respond_with(@widgets)
arroja un HTTP/1.1 500 Internal Server Error
diciendo que la "Plantilla falta".
Solución:
"Plantilla falta" significa que no rinda fue llamado y no exista una plantilla a juego. por accidente, descubrí que está buscando un método de clase ... así que se me ocurrió el siguiente código que funciona, pero no estoy muy contento con él. La tontería está principalmente relacionada con xml = obj.to_myproj_v1_xml(obj)
y la duplicación en el modelo.
Mi pregunta es: ¿alguien ha hecho algo similar de una manera ligeramente más limpia?
- = código actualizado = -
config/inicializadores/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/controladores/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/inicializadores/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:
Encontré otra solución que se siente mejor pero aún un poco extraña (todavía no estoy del todo cómoda con parches de mono), probablemente bien ... básicamente se movió construyendo los datos de respuesta del método de clase to_myproj_v1_json
a un parche de mono en Array. De esta forma, cuando hay una Matriz de widgets, llama al método de instancia as_myproj_v1_json
en cada widget y devuelve toda la matriz como el formato deseado.
Una nota:
- as_json no tiene nada que ver con el formato JSON, sólo crea un hash. Agregue formato personalizado a as_myproj_v1_json (o an_json anule si no está usando tipos de mime personalizados), entonces to_json cambiará un hash a una cadena json.
He actualizado el código siguiente para que sea el que se utiliza actualmente, por lo que la pregunta original puede no tener sentido. si alguien quiere que se muestren la pregunta y el código originales tal como estaban y un código fijo en una respuesta, puedo hacerlo en su lugar.
Tiene una pregunta? No entiendo ... – Anton
Encontré difícil encontrar la pregunta en esta publicación, pero eventualmente la encontré. Sin embargo, si ha llegado a una solución por su cuenta, publíquela como respuesta (y marque como aceptada) antes que actualizar la pregunta. – Kev
@jay, yo diría que debes ser más cuidadoso con la edición de tus publicaciones en el futuro: al llegar a tu pregunta, un visitante es recibido con "ACTUALIZACIÓN: encontró otra solución ..." que es muy confuso. – Ben