Ruby on Rails 高级 JSON 序列化
Posted
技术标签:
【中文标题】Ruby on Rails 高级 JSON 序列化【英文标题】:Ruby on Rails Advanced JSON Serialization 【发布时间】:2010-10-11 02:36:00 【问题描述】:我希望在我的 rails 应用程序中通过 JSON 呈现所有文章的索引以及完整文章,但我在弄清楚如何做到这一点时遇到了一些麻烦。
这是我的控制器:
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
我想在响应中添加所有文章的索引,如下所示:
@index = Article.find(:all, :select => 'id, title')
我能够做到的唯一方法是将索引和文章都放入哈希或数组中,然后将其放入 JSON。
@response = :item => @article, :index => @index
两者的完整代码:
@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
这很好,但现在我无法指定 :include
或 :except
并让它正确呈现。
【问题讨论】:
【参考方案1】:您应该可以像这样嵌套:include
、:except
等:
:except => :item => [ :created_at, :updated_at, :draft, :id, :publish ]...
如果这不起作用,请将其设为对象(例如 OpenStruct)而不是哈希。
-- 马库斯
【讨论】:
【参考方案2】:为了清楚起见,上面的代码与 :include 和 :except 一起使用。通过作品,我的意思是它不会引发错误。问题是它包含索引中每篇文章的 cmets。我只希望包含 :item 的 cmets,而不是索引中列出的任何文章。
我无法将嵌套用作哈希或 OpenStruct 对象。
嵌套在 :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
【讨论】:
【参考方案3】:to_json 有一个 :method 选项,其中包括您命名的任何方法的结果,您可以在该模型上定义一个方法,该方法返回您想要的 JSON 中的其他数据。
【讨论】:
【参考方案4】:您在问题中暗示了解决方案。您很可能希望构建一个散列以呈现为 JSON。现在最好的方法是为 as_json 方法提供一个实现。 as_json 通过构建包含您希望编码的数据的哈希来提供自定义 to_json 输出的正式方法。
关于 as_json 和 to_json 如何交互的更全面的处理可以在Jonathan Julian's weblog 上找到。
【讨论】:
【参考方案5】:(请接受答案)
我认为 nirvdrum 提供的链接包含您的答案。我只回答是因为没有人提到encode_json
。
在您的情况下,您应该只处理as_json
。通过构建一个散列(通过各种调用as_json
)并将其发送到render :json => ...
(不调用to_json
)或者通过简单地在您的模型上实现as_json
并让rails 完成所有工作。 (但我怀疑你会需要前者。)
如果您在渲染的响应中确实需要一些花哨的 js,那么您可以在您的类中实现 encode_json
(同样,不是 to_json
)。例如:
class JsEmptyClosure
def encode_json(*args)
"jQuery[\"noop\"] || function()"
end
def as_json(*args) self end
end
这现在将使用有效的 js 响应 to_json
(但请注意它实际上不是 json)。
【讨论】:
【参考方案6】:感谢您的提问,我可以为具有多个关联的模型自定义我的 json 格式。
渲染 json:@posts.to_json(
:except => [:created_at, :updated_at, :user_id],
:include =>
:user => :only => [:email, :phone],
:location => :only => [:title, :lat, :lon, :street, :city, :state, :邮编],
:上传 => :only => [:image]
)
【讨论】:
【参考方案7】:我建议重载 attributes 方法以返回将在 to_json 输出中自动使用的备用哈希。
class Article
def attributes
... # define your hash that you want to return at the '...'
end
end
对我来说,这似乎比直接使用 to_json 简单得多。
【讨论】:
以上是关于Ruby on Rails 高级 JSON 序列化的主要内容,如果未能解决你的问题,请参考以下文章
Ruby on Rails 序列化然后反序列化 JSON 中的同一个对象
Ruby on Rails:高级搜索,nil:Nilclass 的未定义方法 []