25

前文:

APIのバージョン管理方法を調査し、それを行ういくつかの方法を見つけました。私はpeterwilliamsの提案を試してみることにし、バージョンとフォーマットを指定するために新しいベンダーのmimeタイプを作成しました。「レールウェイ」に従ってこれを行うための明確な記述が見つからなかったので、いくつかの場所からの情報をまとめました。私はそれを機能させることができましたが、レンダラーがウィジェット配列とウィジェットインスタンスを処理する方法にいくつかの間抜けがありますrespond_with

基本的な手順と問題:

mimeタイプを登録し、xmlとjsonの両方でバージョン1のレンダラーをApplicationControllerに追加し、レンダラーの呼び出しto_myproj_v1_xmlto_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はjson形式とは関係がなく、ハッシュを作成するだけです。カスタムフォーマットをas_myproj_v1_json(またはカスタムmimeタイプを使用していない場合はas_jsonオーバーライド)に追加すると、to_jsonはハッシュをjson文字列に変更します。

以下のコードを現在使用されているものに更新したため、元の質問が意味をなさない場合があります。誰かが元の質問とコードをそのまま表示し、応答に修正されたコードが必要な場合は、代わりにそれを行うことができます。

4

2 に答える 2

0

答えについては:質問を参照してください:-)

要するに、さまざまな解決策があり、そのうちの1つが上記の質問にあります。

  • (古い)v1JSONを返すメソッドを実装するためのモンキーパッチ配列
于 2011-08-23T19:51:21.177 に答える
0

このコンテンツタイプのトリックがRailsプロジェクトのどこでも使用されているのを見たことがないので、これは私にとって初めてのことです。私が通常行っているのは、コントローラー(Api :: Version1Controllerなど)に向かうルート名前空間(/ api / v1 /など)を定義することです。

また、あなたが「Railsのやり方」で物事をやりたいと思っていることは知っています。これは、1.3からRailsを使用している人から来たクロッチーな音に聞こえるかもしれませんが、全体respond_with/respond_toものは私にとってかなり魔法です。たとえば、オブジェクトをシリアル化するときにメソッドをrespond_to探す方法を知りませんでした(多分それを読む必要があります)。to_XXXそのようにアレイにモンキーパッチを適用する必要があるのは、かなりばかげているようです。さらに、APIの場合、モデルデータのフォーマットは実際にはビューの仕事であり、モデルの仕事ではありません。この場合、私はrablのようなものを調べるかもしれません。ここにそれについての良い記事があります。

于 2011-08-26T12:32:45.327 に答える