如何在Rails中覆盖to_json?
更新:
这个问题没有得到适当的探索。 真正的问题在于render :json
。
原始问题中的第一个代码粘贴会产生预期的结果。 但是,仍然有一个警告。 看到这个例子:
render :json => current_user
是不一样的
render :json => current_user.to_json
也就是说, render :json
不会自动调用与User对象关联的to_json
方法。 事实上 ,如果to_json
在User
模型上被覆盖, 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
这一切对我来说都很愚蠢。 这似乎告诉我, render
实际上Model#to_json
在指定types:json
时调用Model#to_json
。 有人能解释这里发生了什么吗?
任何可以帮助我的genii可能会回答我的另一个问题: 如何通过在Rails中结合@ foo.to_json(options)和@ bars.to_json(options)来构buildJSON响应
原问题:
我已经看到了一些其他的例子,但我没有做我想要的。
我尝试着:
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
有任何想法吗?
你正在得到ArgumentError: wrong number of arguments (1 for 0)
因为to_json
需要被一个参数, options
哈希覆盖。
def to_json(options) ... end
to_json
, as_json
和渲染的更长的解释:
在ActiveSupport 2.3.3中,增加了as_json
来解决您遇到的问题。 json的创build应该与json的渲染分开。
现在,任何时候在对象上调用as_json
,调用as_json
来创build数据结构,然后使用ActiveSupport::json.encode
将该散列编码为JSONstring。 这发生在所有types:对象,数字,date,string等(请参阅ActiveSupport代码)。
ActiveRecord对象的行为方式相同。 有一个默认的as_json
实现,创build一个包含所有模型属性的散列。 你应该在模型中重写as_json
来创build你想要的JSON结构 。 as_json
,就像旧的to_json
,采用一个选项哈希,你可以指定属性和方法声明。
def as_json(options) # this example ignores the user's options super(:only => [:email, :handle]) end
在你的控制器中, render :json => o
可以接受一个string或一个对象。 如果是string,则作为响应主体传递,如果是对象,则调用as_json
,如上所述触发as_json
。
所以,只要您的模型用as_json
覆盖(或不是)正确地表示,显示一个模型的控制器代码应如下所示:
format.json { render :json => @user }
故事的寓意是: 避免直接调用to_json
,允许render
为你做。 如果你需要调整JSON输出,请调用as_json
。
format.json { render :json => @user.as_json(:only => [:username], :methods => [:avatar]) }
如果你在Rails 3中遇到这个问题,可以重写serializable_hash
而不是as_json
。 这将得到您的XML格式免费也:)
这使我永远不知所措。 希望能帮助别人。
对于不想忽略用户选项的人,也可以添加他们的:
def as_json(options) # this example DOES NOT ignore the user's options super({:only => [:email, :handle]}.merge(options)) end
希望这有助于任何人:)
重写不是to_json,而是as_json。 从as_json打电话你想要什么:
尝试这个:
def as_json { :username => username, :foo => foo, :bar => bar } end