今天看到 @huacnlee 在最新的 homeland 上计划将 active_model_serializers 替换成 jbuilder ,除了这俩个 gem,我之前也用过一段时间 Grape,总的感觉是 active_model_serializers 耍起来还是要比 jbuilder 帅太多,比较符合 Ruby 的气质。
想和大家讨论下如果下一个项目,你会用还是 jbuilder 还是 active_model_serializers?
把这两个作为关键词去 Google 能搜到大量的讨论,以及对比文章,背后的区别无非是理念上的差别,或者从不同的角度看待 JSON 生成这个事情。
jBuilder 把 JSON 视作 view 层的东西,构建复杂的 JSON 对象的时候,可以在适当的时候引入 Presenter 模式/对象。
AMS 把 JSON 视作 model 层的东西,复杂的对象生成可能会用到 Service 模式/对象。
All in all, 无论哪种方式,都是代码组织协调层面的事情,关乎设计,风格,而非技术。
p.s. API Only 模式的 Rails 应用,因为没有 View 层,所以顺理成章的选择 AMS 咯。
此外,实际使用来看 active_modal_serializer 在描述 JSON 结构的时候不清晰(我的感觉)
外加这次这么选 是看到 active_modal_serializer 居然来在依赖 json 1.8 而这个时候 json 2.0.1 都出来了,说明维护不是太勤
大家有没有发现最近 Ruby China 项目的替换,都是尽可能的采用 Rails 的默认方案,目的就一个,减少不必要的依赖,用 Rails 的主厨精选:
推崇主厨精选的思路我也赞同,不过我用过一点 grape,个人感觉 grape 在实现 api server 的时候,确实有很多比较好的实践,比如他的 api 请求参数限制方式;grape entity 的封装 复用,挺灵活,值得学习。 不知道 jbuilder 和 AMS 在同一种对象,不同输出格式的情景里,是不是能做到 grape entity 的这种方式。
其实在我看来 active_modal_serializer 和 jbuilder 都没什么大问题,只是各自表现方式不同,但 jbuilder 能随着 Rails 组的管理获得更快的新版本支持,为何不用呢?
当然 jbuilder 我也是第一次用,不知道会不会有其他的问题,只是目前看起来没什么明显的问题,也挺好用的,从 active_modal_serializer 已有的代码重构也几下就弄好了。
哦,jbuilder 内建类似 ActionView 那种 fragment_cache 的哦,这点用起来很舒服。
而 active_modal_serializer 的 cache 写法到现在我还没搞太明白,好像是有点小问题没搞透
用过 jbuilder 也用过 grape 现在正在用直接用 controller 做 api,不过直观感受是以前用 jbuilder 做 API,随着版本的升级业务的扩展,文件变得越来越多,难以维护 (可能是因为能力问题)
@realwol 同意。Grape 自带参数的 validator,用起来比较省心,而且作为 API 的话,比较方便地描述参数的限制,对客户端开发者来讲也是很赞的。
ActionController::API 还是没有类似 Grape 的参数 validator 和 声明机制,不晓得 @huacnlee 平时是如何使用的? 目前看 rails-api 没有对此支持的计划:https://github.com/rails-api/rails-api/issues/216
#7 楼 @numbcoder 如果只是单纯输出 json,不依赖 gem 直接用 rails 的 json.ruby 模板就行了。。
# views/**/*.json.ruby
obj = {
title: @post.title
}
if user.admin?
obj[:admin] = true
end
obj.to_json
# *_controller.rb
render json: render_to_string('**/*.json.ruby'), content_type: 'application/json'
最近在尝试一种新方案:重写 as_json 的 json_options,根据业务需求去自定义它的 json 结构如下:
self.json_options = {
only: [:xxx],
methods: [:xxx],
include: {
xxx: {......}
}
}
然后 controller 层 index 如下:
render json: {users: @users.as_json}
如果特殊的接口可能需要自定义一些 json 格式
class_attribute :show_json_option
self.show_json_options = {
only: [:xxx],
methods: [:xxx],
include: {
xxx: {......}
}
}
然后 controller 层 index 如下:
render json: @user.as_json(User.show_json_option)
把重 model 发挥到极致