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


94

更新:

この問題は適切に調査されていません。本当の問題は内にありますrender :json

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

render :json => current_user

と同じではありません

render :json => current_user.to_json

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

概要

# 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

これはすべて私にはばかげているようです。これは、タイプが指定されているときrenderに実際には呼び出されていないことを私に言っているようです。誰かがここで実際に何が起こっているのか説明できますか?Model#to_json: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

何か案は?


あなたの例は私のモデルの1つで動作します。usernamefooまたはbarメソッドのいずれかに引数が必要ですか?
ジョナサンジュリアン

いいえ、usernameメソッドではなく、メソッドを必要foobarしません。エラーが発生している場所を示すために質問を更新しました。
マセック

1.8.7を実行しています。そのファイルを開いて、引数がゼロであることを期待するメソッドに引数が渡される理由を確認する必要があります。
ジョナサンジュリアン

回答:


214

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

def to_json(options)
  ...
end

長いの説明to_jsonas_jsonおよびレンダリング:

ActiveSupport 2.3.3では、as_json発生した問題のような問題に対処するために追加されました。json の作成は、jsonのレンダリングとは別にする必要があります

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

ActiveRecordオブジェクトは同じように動作します。as_jsonすべてのモデルの属性を含むハッシュを作成するデフォルトの実装があります。必要なas_jsonJSON構造を作成するには、モデルでオーバーライドする必要があります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]) }

@Jonathan Julian、これはの非常に役立つ説明ですas_json。ActiveRecord :: Serializationのドキュメント(api.rubyonrails.org/classes/ActiveRecord/…)を見るとわかるように、これに関するドキュメントはほとんどありません。私はこれを試してみてます:)
マセック

1
@ジョナサン・ジュリアン、もし私がこれを10回賛成投票できたら、私はそうするでしょう。ここでas_jsonドキュメントはどこにありますか?おかげで再び:)
マセック

71

Rails 3でこれに問題がある場合は、のserializable_hash代わりにオーバーライドしてくださいas_json。これにより、XMLフォーマットも無料で取得できます。

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


1
誰かがこの方法についての良い記事を知っていserializable_hashますか?それを使用すると、後続のxml出力が、オブジェクトをその名前でラップすることから(たとえば、引用オブジェクトの「quote」)、代わりに常に「<hash>」でラップするように変更されます
Tyler Collier

@TylerCollierと同じオプションである必要がありますto_xml
Sam Soffes

この解決策をありがとう!私はruby2 / rails4を使用していて、as_jsonがネストされたオブジェクトで機能していなかった、オーバーライドされたメソッドが 'include'で呼び出されなかった、serializable_hashが機能する!
santuxus 2013

代わりにserializable_hashをオーバーライドする理由の説明については、robots.thoughtbot.com / better- serialization- less-as-jsonをご覧ください。
トファーハント2015

36

ユーザーのオプションを無視したくないだけでなく、それらのオプションも追加したい人のために:

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

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


1
これは私が行う方法ですが、デフォルトのoptionsハッシュを= {}使用しているため、呼び出し時に必要ありません
mroach

4

to_jsonではなく、as_jsonをオーバーライドします。そしてas_jsonからあなたが望むものを呼び出します:

これを試して:

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

as_jsonActiveResourceだけではありませんか?
ジョナサンジュリアン

どうやらActiveRecord :: Serializationにはas_json api.rubyonrails.org/classes/ActiveRecord/Serialization.html
glebm

@glebm、私はこれを試しました、そして私は同じ結果を得ています。質問を更新してあなたに見せます。
マセック

@glebm、私はまだまったく同じエラーを受け取っています。実行してもrender :json => current_user、期待されるデフォルトの結果(UserJSON形式のモデルのすべての属性)が得られます。私は追加するとas_json、私にメソッドをUserモデルと同じことをしてみてください、私は:(エラーを取得する
マセック

@glebm、ありがとう。私は何か間違ったことをしていたことを知っています。更新された質問をチェックする価値があるかもしれません。
マセック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.