web-dev-qa-db-ja.com

Railsでto_jsonをオーバーライドする方法は?


更新:

この問題は適切に調査されていません。実際の問題は_render :json_内にあります。

元の質問の最初のコードを貼り付けると、期待どおりの結果が得られます。ただし、まだ注意が必要です。この例を参照してください。

_render :json => current_user_

is[〜#〜] not [〜#〜]と同じ

_render :json => current_user.to_json_

つまり、_render :json_は、Userオブジェクトに関連付けられた_to_json_メソッドを自動的に呼び出しません。 実際にUserモデルで_to_json_がオーバーライドされている場合、_render :json => @user_は以下に説明するArgumentErrorを生成します。

概要

_# works if User#to_json is not overridden
render :json => current_user

# If User#to_json is overridden, User requires explicit call
render :json => current_user.to_json
_

これはすべて私には馬鹿げているようです。これは、タイプ_Model#to_json_が指定されているときに、renderが実際に_:json_を呼び出していないことを教えているようです。誰かがここで実際に何が起こっているのか説明できますか?

これで私を助けることができるgeniiは、おそらく他の質問に答えることができます: Railsの@ foo.to_json(options)と@ bars.to_json(options)を組み合わせてJSON応答を作成する方法


元の質問:

SOの他の例をいくつか見てきましたが、私が探していることは何もしません。

私はしようとしています:

_class User < ActiveRecord::Base

  # this actually works! (see update summary above)
  def to_json
    super(:only => :username, :methods => [:foo, :bar])
  end

end
_

ArgumentError: wrong number of arguments (1 for 0)を取得しています

_/usr/lib/Ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json
_

何か案は?

92
maček

_to_json_は1つのパラメーター、optionsハッシュでオーバーライドする必要があるため、ArgumentError: wrong number of arguments (1 for 0)を取得しています。

_def to_json(options)
  ...
end
_

_to_json_、_as_json_、およびレンダリングの詳細説明:

ActiveSupport 2.3.3では、遭遇したような問題に対処するために_as_json_が追加されました。 jsonのcreationは、jsonのrenderingとは別にする必要があります。

これで、オブジェクトで_to_json_が呼び出されるたびに、_as_json_が呼び出されてデータ構造が作成され、そのハッシュが_ActiveSupport::json.encode_を使用してJSON文字列としてエンコードされます。これは、オブジェクト、数値、日付、文字列など、すべてのタイプで発生します(ActiveSupportコードを参照)。

ActiveRecordオブジェクトは同じように動作します。すべてのモデルの属性を含むハッシュを作成するデフォルトの_as_json_実装があります。 モデルで_as_json_をオーバーライドして、必要なJSON構造を作成する必要があります。 _as_json_は、古い_to_json_と同様に、宣言的に含める属性とメソッドを指定できるオプションハッシュを受け取ります。

_def as_json(options)
  # this example ignores the user's options
  super(:only => [:email, :handle])
end
_

コントローラでは、_render :json => o_は文字列またはオブジェクトを受け入れることができます。 文字列の場合、応答本文として渡され、オブジェクトの場合、_to_json_が呼び出され、上記で説明したように_as_json_がトリガーされます。

したがって、モデルが_as_json_オーバーライドで適切に表される(または表されない)限り、1つのモデルを表示するコントローラーコードは次のようになります。

_format.json { render :json => @user }
_

ストーリーの教訓は次のとおりです:_to_json_を直接呼び出すのを避け、renderがあなたのためにそれを行うことを許可します。 JSON出力を調整する必要がある場合は、_as_json_。を呼び出します

_format.json { render :json => 
    @user.as_json(:only => [:username], :methods => [:avatar]) }
_
208
Jonathan Julian

Rails 3でこれに問題がある場合、serializable_hash の代わりに as_json。これにより、XMLフォーマットも無料で取得できます。

これは私が永遠に理解するのにかかりました。それが誰かを助けることを願っています。

71
Sam Soffes

ユーザーのオプションを無視したくないが、ユーザーのオプションも追加したい場合:

def as_json(options)
  # this example DOES NOT ignore the user's options
  super({:only => [:email, :handle]}.merge(options))
end

これが誰にも役立つことを願っています:)

33
Danpe

To_jsonではなく、as_jsonをオーバーライドします。そして、as_jsonから必要なものを呼び出します。

これを試して:

def as_json 
 { :username => username, :foo => foo, :bar => bar }
end
3
glebm