JSON 模板
作为一些背景知识,我正处于大型 RoR 的早期设计阶段 我工作的公司的项目,我们计划坚持下去 未来5-10年的铁路。我们正处于项目的这个阶段 我们正在尝试获得一些好的实践并定制框架 为我们需要的东西而工作。我们考虑过 使用完整的网络应用程序(Backbone.js 风格)与 a 的优点/缺点 基于静态受限 JS 的 Rails 应用程序。虽然我们很想去 对于 web 应用程序,我确定使用 Backbone.js 会 原因:
- 视图和路由完全重复(从长远来看是一个维护问题)
- 难以跟踪多态关联及其路由
- 不允许我们在客户端使用视图助手 (维护问题)
- 一些模型信息重复
- 客户端计算机速度慢(超出我们的控制范围),这会 运行困难
为了尝试减少这种情况,我们决定采用更加混合的方式 方法,但将更多逻辑推回服务器端,同时 仍然保持 RESTFUL 架构作为 API 的最佳状态 可能的。我们计划完成初始页面加载 通常使用 Rails,然后页面上的任何操作都会发送 通过 AJAX 请求并接收返回一个 JSON 对象,其中包含 渲染部分,以及一些附加信息(即闪存更新, 对象的 JSON 表示,附加 JS 包括 if 必要的等等)
我们遇到的问题是,根据我的理解,我们 无法维护RESTFUL架构并且有多个 相同数据的部分/视图。举个例子,如果我想要 通过orders/index从服务器请求订单列表,它将 仅返回数据的一种视图。如果我有一个扩展的桌子,一个列表, 或其他一些我想要请求的部分的视图/部分/小部件 用于.
为此,我添加了一个 params[:partial] (它是一个附加组件 在路由或 url 参数上)为服务器提供 所请求的信息以及我的观点 我期待着它的到来。但是,这本身就可以很好地发挥作用 我还希望收到来自 同时更新服务器(即闪存更新,JSON 表示形式) 数据等)。理想情况下,我们希望它是灵活、快速且向下发送的 来自服务器的 JSON 格式。
为此,我重写了现有的 JSON 响应程序,如下所示: 你可能会注意到我不得不使用它来渲染 JSON 中的 HAML/ERB 模板:
module ExtraFunctions
def partial_options
params.include?(:partial) ? { :partial => params[:partial] } : {}
end
def flash_options
{ :file => 'layouts/_flash.html.haml' }
end
end
ApplicationController.send :include, ExtraFunctions
#I would love to be using the ERB templating and views
#instead of this kludge. But this will have to do.
ActionController::Renderers.add :json do |json, options|
#Change the format so we can render the html templates
self.formats = [:html]
options = { :layout => false }
partial_opt = options.merge(self.respond_to?(:partial_options) ? self.partial_options : {})
flash_opt = options.merge(self.respond_to?(:flash_options) ? self.flash_options : {})
obj = {
json: json.as_json,
partial: render_to_string(partial_opt),
flash: flash,
flash_partial: render_to_string(flash_opt),
user: @current_user
#js-includes: #Working on this
}
#Change the format back
self.formats = [:json]
json = obj.to_json(options) unless obj.kind_of?(String)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
self.content_type ||= Mime::JSON
json
end
您会注意到其中有一个 js-includes 的位置,原因是 也就是说,我希望能够在后期进行动态包含 使用 head.js 进行游戏。这将是为了更容易的依赖管理, 因为最初的视图不会包括一些部分 通过 AJAX 请求(即,如果我抓取一个表单来输入新的 地址,并且该表单对其进行了一些 AJAX 检查,如 在其顶部使用 content_for 标签)。理想情况下,我真正想要的 这是一个 JSON 布局,看起来像(尽管有更多 我希望是糖衣语法):
** json/application.json.erb **
{
json: <%= json.as_json %>,
partial: <%= render_to_string(partial_opt) %>,
flash: <%= flash %>,
flash_partial: <%= render_to_string(flash_opt) %>,
user: <%= @current_user =>,
js-includes: <%= yield :js_includes %>,
<%= yield =>
}
我已经研究这些考虑/问题有一段时间了,我的 问题有两个:
1)我们的行为是否有任何明显愚蠢的地方 正在做?有更好或更标准的解决方案吗?
2) 有没有办法让 ERB 渲染 JSON 模板?
谢谢!
As a bit of background, I'm in the early design phases of a large RoR
project for the company I work for and we're planning on sticking with
Rails for the next 5-10 years. We're at this point in the project
we're trying to get some good practices and customize the framework to
work for what we're going to be needing need. We've considered the
pros/cons of going with a full blown web-app (Backbone.js style) vs. a
static limited JS based Rails app. While we would have loved to go
with a webapp, I've determined that going with Backbone.js would
cause:
- Complete duplication of views and routes (a maintenance issue in the long run)
- Difficulty tracking polymorphic associations and their routes
- Wouldn't allow us to use the view helpers on the client side
(maintenance issue) - Duplication of some of the model information
- Slow client-end computers (beyond our control), which would have
difficulty running it
To try and reduce this, we're decided to go with a more hybrid
approach but to push more of the logic back to the server side while
still maintaining a RESTFUL architecture as an API as best as
possible. We're planning on having the initial page loads done
normally using Rails, and then any manipulations on the page send the
request via AJAX and receiving back a JSON object which contains the
rendered partial, and some additional information (ie. flash updates,
JSON representation of the object, additional JS includes if
necessary, etc.)
The problem we're running into, is that from my understanding, we
cannot maintain the RESTFUL architecture and have multiple
partials/views for that same data. As an example of this, if I wanted
to request a list of Orders from the server via orders/index, it would
return only one view of the data. If I had an extended table, a list,
or some other view/partial/widget which I wanted the requested partial
to be used for.
To that end, I've added a params[:partial] (which is either an add-on
on the route, or a url parameter) that provides the server both with
the information that is being requested, as well as the view which I
am expecting it to come in. This would work well on it's own, however
I'd also like to have any additional information sent down from the
server at the same time (ie. flash updates, JSON representation of the
data, etc.). Ideally we want this to be flexible, fast, and sent down
from the server in JSON format.
To that end, I've overriden the existing JSON responder as follows,
and you may notice the hack I've had to use to have it render the
HAML/ERB templates inside of the JSON:
module ExtraFunctions
def partial_options
params.include?(:partial) ? { :partial => params[:partial] } : {}
end
def flash_options
{ :file => 'layouts/_flash.html.haml' }
end
end
ApplicationController.send :include, ExtraFunctions
#I would love to be using the ERB templating and views
#instead of this kludge. But this will have to do.
ActionController::Renderers.add :json do |json, options|
#Change the format so we can render the html templates
self.formats = [:html]
options = { :layout => false }
partial_opt = options.merge(self.respond_to?(:partial_options) ? self.partial_options : {})
flash_opt = options.merge(self.respond_to?(:flash_options) ? self.flash_options : {})
obj = {
json: json.as_json,
partial: render_to_string(partial_opt),
flash: flash,
flash_partial: render_to_string(flash_opt),
user: @current_user
#js-includes: #Working on this
}
#Change the format back
self.formats = [:json]
json = obj.to_json(options) unless obj.kind_of?(String)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
self.content_type ||= Mime::JSON
json
end
You'll notice there is a spot in there for js-includes, the reason for
that is that I want the ability to have dynamic includes late in the
game using head.js. This would be for easier dependency management,
as the initial view would not be including some of the partials that
are requested via AJAX (ie. if I grabbed a form to enter a new
address, and that form has some AJAX checking on it as included in the
top of it using a content_for tag). Ideally, what I'd really like
this to be is a JSON layout to look something like (though with a more
sugar coated syntax I would hope):
** json/application.json.erb **
{
json: <%= json.as_json %>,
partial: <%= render_to_string(partial_opt) %>,
flash: <%= flash %>,
flash_partial: <%= render_to_string(flash_opt) %>,
user: <%= @current_user =>,
js-includes: <%= yield :js_includes %>,
<%= yield =>
}
I've been working on these considerations/issues for a while, and my
questions are two:
1) Is there anything blatantly screamingly stupid about what we're
doing? Is there a better or more standard solution?
2) Is there a way to have ERB render the templates for JSON?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
底线是,这是一个常见问题,目前还没有强烈的解决方案。
David Heinemeier Hansson 在 RailsConf 2011 上介绍了 Rails 3.1 中的新资产管道时谈到了这个问题,并指出他们已经开始使用他们所谓的 pjax 来处理页面的刷新部分,并建议它及时成为 Rails 的一部分。
37signals 还构建了 Cinco(全 js 移动应用框架)并计划将其开源,但我相信他们已经开始偏离他们构建它的一些想法,所以我不知道状态是。
Bottom line, this is a common problem that there isn't yet a strong opinion on solving.
David Heinemeier Hansson talked about this problem a bit at RailsConf 2011 when he introduced the new Asset Pipeline in Rails 3.1, noting that they've started using what they call pjax to handle refreshing parts of a page and suggested it'd be part of Rails in time.
37signals has also built Cinco (all-js mobile-app framework) and was planning on open sourcing it, but I believe they've started growing away from some of the ideas they were building it with, so I don't know what the status is.