rails 3 响应格式和版本控制在 Accept 标头中使用供应商 MIME 类型 [英] rails 3 response format and versioning using vendor MIME type in the Accept header

查看:15
本文介绍了rails 3 响应格式和版本控制在 Accept 标头中使用供应商 MIME 类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

序言:

我研究了如何对 API 进行版本控制,并找到了几种方法.我决定尝试 peter williams' 的建议并创建了新的供应商mime 类型来指定版本和格式.我找不到按照轨道方式"执行此操作的确定性文章,因此我从几个地方拼凑了信息.我能够让它工作,但是渲染器在 respond_with 中处理 Widget 数组与 Widget 实例的方式有些愚蠢.

I investigated how to version an API and found several ways to do it. I decided to try peter williams' suggestion and created new vendor mime types to specify version and format. I could find no definitive write-up for doing this following "the rails way" so I pieced together info from several places. I was able to get it working, but there is some goofiness in the way the renderers handle Widget array vs Widget instance in respond_with.

基本步骤&问题:

我在 xml 和 json 中注册了 mime 类型并将版本 1 的渲染器添加到 ApplicationController,渲染器调用模型中的 to_myproj_v1_xmlto_myproj_v1_json 方法.respond_with(@widget) 工作正常,但 respond_with(@widgets) 抛出一个 HTTP/1.1 500 Internal Server Error 说模板丢失"".

I registered mime types and added renderers for version 1 in both xml and json to ApplicationController, the renderers call to_myproj_v1_xml and to_myproj_v1_json methods in the model. respond_with(@widget) works fine but respond_with(@widgets) throws an HTTP/1.1 500 Internal Server Error saying that the "Template is missing".

解决方法:

模板丢失"意味着没有调用渲染并且不存在匹配的模板.偶然地,我发现它正在寻找一个类方法......所以我想出了下面的代码,但我对它并不满意.愚蠢的主要是与 xml = obj.to_myproj_v1_xml(obj) 和模型中的重复有关.

"Template is missing" means that no render was called and no matching template exists. by accident, I discovered that it is looking for a class method... so I came up with the code below which works but I'm not really happy with it. The goofiness is mostly in and related to xml = obj.to_myproj_v1_xml(obj) and the duplication in the model.

我的问题是 - 有没有人以更简洁的方式做过类似的事情?

My question is - has anyone done anything similar in a slightly cleaner fashion?

-= 更新代码 =-

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 到 Array 上的猴子补丁.这样,当有一个小部件数组时,它会在每个小部件上调用实例方法 as_myproj_v1_json 并根据需要的格式返回整个数组.

Found another solution that feels better but still a little weird (I'm still not completely comfortable with monkey patches), probably ok though... basically moved building the response data from the class method to_myproj_v1_json to a monkey patch on Array. This way when there is an Array of Widgets, it calls the instance method as_myproj_v1_json on each Widget and returns the whole Array as desired format.

注意事项:

  • as_json 与 json 格式无关,只是创建了一个哈希.将自定义格式添加到 as_myproj_v1_json(或 as_json 覆盖,如果您不使用自定义 mime 类型),那么 to_json 会将哈希更改为 json 字符串.

我已将下面的代码更新为当前使用的代码,因此最初的问题可能没有意义.如果有人想要原始问题和代码显示为原样并在回复中修复代码,我可以这样做.

i have updated the code below to be what is currently used, so the original question may not make sense. if anyone wants the original question and code shown as was and fixed code in a response i can do that instead.

推荐答案

答案:看问题 :-)

简而言之,有不同的解决方案,其中一个在上面的问题中:

In short, there are different solutions, of which one is in the question above:

  • Monkey-patch Array 来实现一种方法,该方法将返回(旧)v1 JSON

这篇关于rails 3 响应格式和版本控制在 Accept 标头中使用供应商 MIME 类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆