`

Rails 3.2 的 Ajax 向导

 
阅读更多

原文: http://chloerei.com/2012/04/21/rails-3-2-ajax-guide/

 

Rails Ajax 的两种类型

在 Rails 里面处理 Ajax 大致可以分为两种:

  1. UJS:服务端返回 Javascript,客户端收到后直接执行
  2. JSON API:服务端返回数据,客户端收到后本地处理再执行

Rails 自带的 UJS 机制在提供少量 AJAX 操作的时候很便利。如果你只想写 Javascript 原生的 Ajax,或者需要为客户端应用提供 API,那么应该了解 JSON API 方式。

UJS

先看一段代码,这是一个常见的回复表单:

<%= form_for @reply do |f| %>
<%= f.text_area :body %>
<% end %>

对应的 action 如下:

# POST /replies
def create
  @reply = @topic.replies.new params[:reply].merge(:user => current_user)
  if @reply.save
    redirect_to @topic
  else
    render :new
  end
end

创建回复的时候,如果成功,服务端会要求重定向到话题页面,如果不成功,服务器会渲染 :new 页面,让用户再次编辑。

现在用 UJS 方式改写它,回复成功的时候,将回复添加到页面回复列表的后面,否则显示一条错误信息。

首先,为表单添加一个 :remote 参数:

<%= form_for @reply, :remote => true do |f| %>
<%= f.text_area :body %>
<% end %>

:remote 设置为 true 后,Rails 的 form_for helper 会插入一个 data-remote=true 属性,这样它自带的 rails_ujs.js 模块会自动为这个表单开启 UJS 方式的 Ajax。如果你想知道这魔法是怎么实现的,可以去看看 jquery-ujs 的源码。

然后,在对应 action 里加上 respond_toformat.js 代码块:

# POST /replies
def create
  @reply = @topic.replies.new params[:reply].merge(:user => current_user)
  respond_to do |format| # <- 这里
    if @reply.save
      format.html { redirect_to @topic }
      format.js # <- 这里
    else
      format.html { render :new }
      format.js # <- 还有这里
    end
  end
end

加入 respond_to 代码块后,Rails 会分辨客户端请求格式是 html 还是 js,不同格式请求返回不同的内容。这里的 format.js 表示请求 js 格式的时候按照约定渲染名为 create.js.erb 的模板。

最后,添加一个 create.js.erb 模板:

<% if @reply.errors.empty? %>
  $('<%= j(render :partial => 'reply', :object => @reply) %>').appendTo($('#replies'));
<% else %>
  alert('@reply.errors.full_messages.join(',')');
<% end %>

这个模板区分了 @reply 保存成功和失败的两种情况,保存成功的时候,新回复会被添加到回复列表的后面,否则会弹出一条错误信息。

JSON API

UJS 的好处是代码量少,可以复用服务端的模板,但不适用于重客户端的场景。现在来看 Rails 提供 JSON API 的方法。

修改 action,添加 format.json

# POST /replies
def create
  @reply = @topic.replies.new params[:reply].merge(:user => current_user)
  respond_to do |format|
    if @reply.save
      format.html { redirect_to @topic }
      format.js { render :layout => false }
      format.json { render :json => @reply } # <- 这里
    else
      format.html { render :new }
      format.js { render :layout => false, :status => 406  }
      format.json { render :json => {:errors => @reply.errors.full_messages.join(',')} } # <- 还有这里
    else
    end
  end
end

添加这两行后,这个 action 就能处理 JSON 请求了。这个例子没有涉及 API 数据结构设计,如果你需要调整所返回的 JSON 数据的结构,我推荐 jbuilder 模板。

2013-11-19 更新:jbuilder 是 Rails 4 默认带的 gem。

假设我们用 jQuery.ajax 实现客户端逻辑,那么会有类似代码:

$('new_reply_form').on('submit', function(event){
  $.ajax({
    url: $(this).prop('action'),
    dataType: 'json'
  }).done(function(data) {
    /* 本地逻辑 */
  });
})

.done callback 中获取的 data 就是 JSON API 返回的数据。

该用哪种实现?

如果网站以后端为主,只需要简单的 Ajax 页面更新操作,那么适用 UJS。如果是从前端框架起步,打算搭建重客户端应用,那么适用 JSON API。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics