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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:01:19  来源:igfitidea点击:

Ruby on Rails Advanced JSON Serialization

ruby-on-railsrubyjsonserializationxml-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 简单得多。