Ruby on Rails 高级 JSON 序列化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/607873/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby on Rails Advanced JSON Serialization
提问by nirvdrum
I'm looking to render an index of all articles along with a full article via JSON in my rails app, but I'm having a little trouble figuring out how to do it.
我希望在我的 rails 应用程序中通过 JSON 呈现所有文章的索引以及一篇完整的文章,但我在弄清楚如何做到这一点时遇到了一些麻烦。
Here is my controller now:
这是我的控制器:
if params[:id]
@article = Article.find(params[:id])
else
@article = Article.published.not_draft.by_recent.first
end
respond_to do |format|
format.js { render :json => @article.to_json(
:except => [ :created_at, :updated_at, :draft, :id, :publish ],
:include => {
:comments => {
:only => [:body]
}
}),
:callback => params[:callback]}
end
What I'd like to do in the response is add an index of all articles, like so:
我想在响应中做的是添加所有文章的索引,如下所示:
@index = Article.find(:all, :select => 'id, title')
The only way I've been able to do it, is put both the index and article into a hash or array and then put that to JSON.
我能够做到的唯一方法是将索引和文章都放入哈希或数组中,然后将其放入 JSON。
@response = { :item => @article, :index => @index }
Full code with both:
两者的完整代码:
@index = Article.find(:all, :select => 'id, title')
if params[:id]
@article = Article.find(params[:id])
else
@article = Article.published.not_draft.by_recent.first
end
@response = { :item => @article, :index => @index }
respond_to do |format|
format.js { render :json => @response.to_json(), :callback => params[:callback]}
end
This would be fine, except now I cannot specify :includeor :exceptand get it to render properly.
这会很好,除非现在我无法指定:include或:except让它正确呈现。
回答by nirvdrum
You hint at the solution in your question. You most likely want to build up a hash to render to JSON. The preferred way of doing this now is by providing an implementation for the as_json method. as_json provides a formal means of customizing to_json output by building up a hash containing the data you wish to encode.
您在问题中暗示了解决方案。您很可能希望建立一个哈希值来呈现为 JSON。现在这样做的首选方法是提供 as_json 方法的实现。as_json 通过构建一个包含您希望编码的数据的散列,提供了一种自定义 to_json 输出的正式方法。
A more thorough treatment of how as_json and to_json interact can be found on Jonathan Julian's weblog.
可以在Jonathan Julian 的博客上找到对 as_json 和 to_json 如何交互的更全面的处理。
回答by nirvdrum
Just to be clear the code above works with the :include and :except. And by works I mean it doesn't throw an error. The problem is it includes comments for every article in the index. I'm only looking to include comments for the :item and not any of the articles listed in the index.
为了清楚起见,上面的代码适用于 :include 和 :except。通过作品,我的意思是它不会引发错误。问题是它包括索引中每篇文章的评论。我只想包括对 :item 的评论,而不是索引中列出的任何文章。
I couldn't get nesting to work as a hash or an OpenStruct object.
我无法将嵌套用作散列或 OpenStruct 对象。
Nesting on :include throws an error, nesting on :except doesn't throw an error, but nothing is filtered out, :created_at, etc. still show up.
在 :include 上嵌套会抛出错误,在 :except 上嵌套不会抛出错误,但没有过滤掉任何内容,:created_at 等仍然显示。
...
@response = { :item => @article, :index => @index }
format.js { render :json => @response.to_json(
:except => {:item => [ :created_at, :updated_at, :draft, :id, :publish ]},
:include => { :item => {
:comments => {
:only => [:body]
}
}}),
:callback => params[:callback]}
end
回答by DavidNorth
to_json has a :method option that includes the result of any method you name, you could define a method on that model that returns the additional data you want in your JSON.
to_json 有一个 :method 选项,其中包含您命名的任何方法的结果,您可以在该模型上定义一个方法,该方法返回您想要的 JSON 中的其他数据。
回答by MarkusQ
You should be able to nest the :include, :except, etc. like so:
你应该能够巢:include,:except等像这样:
:except => {:item => [ :created_at, :updated_at, :draft, :id, :publish ]}...
If that doesn't work, make it an object (e.g. an OpenStruct) instead of a hash.
如果这不起作用,请将其设为对象(例如 OpenStruct)而不是散列。
-- Markus
——马库斯
回答by Corin
(Please accept an answer)
(请采纳答案)
I think that the link that nirvdrum gave holds your answer. I only answer because nobody has mentioned encode_json.
我认为 nirvdrum 提供的链接包含您的答案。我只是回答,因为没有人提到encode_json。
In your case you should only be dealing with as_json. Either by building a hash (with various calls to as_json) and sending that to render :json => ...(without the call to to_json) or by simply implementing as_jsonon your model and letting rails do all the work. (But I suspect you'll need the former.)
在您的情况下,您应该只处理as_json. 要么通过构建一个散列(通过各种调用as_json)并将其发送到render :json => ...(不调用to_json)要么通过简单地as_json在您的模型上实现并让 Rails 完成所有工作。(但我怀疑你会需要前者。)
If you really need some fancy js in your rendered response then you can implement encode_jsonin your classes (again, not to_json). For example:
如果你真的需要在你的渲染响应中使用一些花哨的 js,那么你可以encode_json在你的类中实现(同样,不是to_json)。例如:
class JsEmptyClosure
def encode_json(*args)
"jQuery[\"noop\"] || function(){}"
end
def as_json(*args) self end
end
This will now respond to to_jsonwith valid js (but note it's not actually json).
这现在将响应to_json有效的 js(但请注意它实际上不是 json)。
回答by Guoqiang Huang
Thanks for the question, I am able to customize my json format for a model with several associations.
感谢您的提问,我可以为具有多个关联的模型自定义 json 格式。
render json: @posts.to_json(
:except => [ :created_at, :updated_at, :user_id ],
:include => {
:user => {:only => [:email, :phone]},
:location => {:only => [:title, :lat, :lon, :street, :city, :state, :zipcode]},
:uploads => {:only => [:image]}
}
)
渲染 json:@posts.to_json(
:except => [ :created_at, :updated_at, :user_id ],
:include => {
:user => {:only => [:email, :phone]},
:location => {:only => [:title, :lat, :lon, :street, :city, :state, :zipcode]},
:uploads => {:only => [:image]}
}
)
回答by Kevin Bullaughey
I would recommend overloading the attributes method to return an alternat hash that will be automatically used in to_json output.
我建议重载属性方法以返回将在 to_json 输出中自动使用的替代哈希。
class Article
def attributes
{ ... } # define your hash that you want to return at the '...'
end
end
To me this seems much simpler than mucking around with to_json directly.
对我来说,这似乎比直接使用 to_json 简单得多。

