25 votes

rails 3 format de la réponse et la gestion des versions à l'aide de vendeur type MIME dans l'en-tête Accept

Préambule:

J'ai étudié comment la version de l'API et a trouvé plusieurs façons de le faire. J'ai décidé d'essayer peter williams suggestion et a créé de nouveaux fournisseurs de types mime pour spécifier la version et le format. Je n'ai trouvé aucun définitive écriture-up pour faire ce qui suit "les rails de chemin", j'ai donc rassemblé des informations à partir de plusieurs endroits. J'ai été en mesure d'obtenir ce travail, mais il y a certains goofiness dans la façon dont les moteurs de rendu poignée Widget de tableau de vs instance Widget en respond_with.

Étapes de base & problème:

J'ai enregistré les types mime et ajouté les moteurs de rendu pour la version 1 à la fois en xml et json pour ApplicationController, les convertisseurs appel to_myproj_v1_xml et to_myproj_v1_json méthodes dans le modèle. respond_with(@widget) fonctionne très bien mais respond_with(@widgets) jette un HTTP/1.1 500 Internal Server Error dire que le "Modèle " manque".

Solution de contournement:

"Le modèle est manquant" signifie qu'aucun rendu a été appelé et aucune correspondance, modèle existe. par hasard, j'ai découvert qu'il est à la recherche d'une méthode de classe... alors je suis venu avec le code ci-dessous qui fonctionne, mais je ne suis pas vraiment heureux avec elle. La goofiness est surtout dans et liés à l' xml = obj.to_myproj_v1_xml(obj) de la duplication dans le modèle.

Ma question est, est-ce quelqu'un fait quelque chose de semblable dans un peu de nettoyant à la mode?

-= mise à jour du code =-

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

Mise à JOUR:

Trouvé une autre solution qui se sent mieux, mais toujours un peu bizarre (je ne suis pas encore complètement à l'aise avec le singe patchs), probablement ok, bien... en fait déplacé la construction de la réponse des données à partir de la méthode de la classe to_myproj_v1_json à un singe patch sur le Tableau. De cette façon, quand il y a un Tableau de Widgets, il appelle la méthode d'instance as_myproj_v1_json sur chaque Widget et renvoie l'ensemble du Tableau en tant que format de votre choix.

Une remarque:

  • as_json n'a rien à voir avec le format json, juste crée une table de hachage. Ajouter une mise en forme personnalisée à as_myproj_v1_json (ou un as_json remplacer si vous n'êtes pas en utilisant des types mime), puis to_json va changer un hash d'une chaîne json.

j'ai mis à jour le code ci-dessous à ce qui est actuellement utilisé, de sorte que la question d'origine ne peut faire sens. si l'on veut de la question d'origine et le code représentés comme et code fixe dans une réponse que je peux faire à la place.

0voto

Daan Points 3325

Pour la réponse: voir la question :-)

En bref, il existe différentes solutions, dont l'une est dans la question ci-dessus:

  • Singe-patch Tableau pour mettre en œuvre une méthode qui donne les (vieux) v1 JSON dos

0voto

Elliot Winkler Points 1141

Je n'ai pas vu ce type de contenu astuce utilisée n'importe où dans un des Rails de projet avant, donc c'est nouveau pour moi. La façon dont je l'ai souvent vu faire est de définir un parcours de l'espace de noms (par exemple, /api/v1/) qui va à un contrôleur (par exemple, l'Api::Version1Controller).

Aussi, je sais que vous voulez faire les choses "Rails de chemin", et peut-être que cela semble grognon venant d'un gars qui a été avec des Rails depuis la 1.3, mais l'ensemble de l' respond_with / respond_to stuff est plutôt de la magie pour moi. Je ne savais pas qu' respond_to recherche un to_XXX méthode lorsque l'on sérialise les objets, par exemple (peut-être que j'ai besoin de lire jusqu'à que). Avoir de singe-patch Tableau comme cela semble assez stupide. En outre, pour une API, la mise en forme des données du modèle qui est vraiment le point de vue de l'emploi, pas le modèle. Je pourrais regarder dans quelque chose comme rabl dans ce cas. Il y a un bon article à ce sujet ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X