如何在 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
这对我来说似乎很愚蠢。这似乎告诉我,当指定类型 :json
时,render
实际上并未调用 Model#to_json
。有人能解释一下这里到底发生了什么吗?
任何可以帮助我解决这个问题的天才都可能回答我的其他问题: 如何通过在 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
我在
/usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json
“任何想法?”中收到 ArgumentError: 错误数量的参数(1 代表 0)
Update:
This issue was not properly explored. The real issue lies within render :json
.
The first code paste in the original question will yield the expected result. However, there is still a caveat. See this example:
render :json => current_user
is NOT the same as
render :json => current_user.to_json
That is, render :json
will not automatically call the to_json
method associated with the User object. In fact, if to_json
is being overridden on the User
model, render :json => @user
will generate the ArgumentError
described below.
summary
# 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
This all seems silly to me. This seems to be telling me that render
is not actually calling Model#to_json
when type :json
is specified. Can someone explain what's really going on here?
Any genii that can help me with this can likely answer my other question: How to build a JSON response by combining @foo.to_json(options) and @bars.to_json(options) in Rails
Original Question:
I've seen some other examples on SO, but I none do what I'm looking for.
I'm trying:
class User < ActiveRecord::Base
# this actually works! (see update summary above)
def to_json
super(:only => :username, :methods => [:foo, :bar])
end
end
I'm getting ArgumentError: wrong number of arguments (1 for 0)
in
/usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您将收到
ArgumentError:参数数量错误 (1 for 0)
,因为to_json
需要用一个参数(即options
哈希)覆盖。对
to_json
、as_json
和渲染的详细说明:在 ActiveSupport 2.3.3 中,添加了
as_json
来解决问题就像你遇到的那个人一样。 json 的创建应该与json的渲染分开。现在,每当对对象调用
to_json
时,都会调用as_json
来创建数据结构,然后使用ActiveSupport: 将该哈希编码为 JSON 字符串: json.encode
。所有类型都会发生这种情况:对象、数字、日期、字符串等(请参阅 ActiveSupport 代码)。ActiveRecord 对象的行为方式相同。有一个默认的
as_json
实现,它创建一个包含所有模型属性的哈希。 您应该覆盖模型中的as_json
以创建所需的 JSON 结构。as_json
与旧的to_json
一样,采用选项哈希,您可以在其中指定要以声明方式包含的属性和方法。在你的控制器中,
render :json =>; o
可以接受字符串或对象。 如果它是一个字符串,它会作为响应正文传递,如果它是一个对象,则调用to_json
,这会触发as_json
,如上所述。因此,只要您的模型正确地用
as_json
覆盖(或不覆盖)表示,显示一个模型的控制器代码应该如下所示:这个故事的寓意是:避免调用 <直接使用 code>to_json ,允许
render
为您执行此操作。如果您需要调整 JSON 输出,请调用as_json
。You are getting
ArgumentError: wrong number of arguments (1 for 0)
becauseto_json
needs to be overridden with one parameter, theoptions
hash.Longer explanation of
to_json
,as_json
, and rendering:In ActiveSupport 2.3.3,
as_json
was added to address issues like the one you have encountered. The creation of the json should be separate from the rendering of the json.Now, anytime
to_json
is called on an object,as_json
is invoked to create the data structure, and then that hash is encoded as a JSON string usingActiveSupport::json.encode
. This happens for all types: object, numeric, date, string, etc (see the ActiveSupport code).ActiveRecord objects behave the same way. There is a default
as_json
implementation that creates a hash that includes all the model's attributes. You should overrideas_json
in your Model to create the JSON structure you want.as_json
, just like the oldto_json
, takes an option hash where you can specify attributes and methods to include declaratively.In your controller,
render :json => o
can accept a string or an object. If it's a string, it's passed through as the response body, if it's an object,to_json
is called, which triggersas_json
as explained above.So, as long as your models are properly represented with
as_json
overrides (or not), your controller code to display one model should look like this:The moral of the story is: Avoid calling
to_json
directly, allowrender
to do that for you. If you need to tweak the JSON output, callas_json
.如果您在 Rails 3 中遇到此问题,请覆盖
serialized_hash
而不是as_json
。这也将免费获得您的 XML 格式:)If you're having issues with this in Rails 3, override
serializable_hash
instead ofas_json
. This will get your XML formatting for free too :)对于那些不想忽略用户选项但又添加他们的选项的人:
希望这对任何人都有帮助:)
For people who don't want to ignore users options but also add their's:
Hope this helps anyone :)
不是覆盖 to_json,而是覆盖 as_json。
并从 as_json 调用你想要的:
试试这个:
Override not to_json, but as_json.
And from as_json call what you want:
Try this: