如何响应没有erb.js的AJAX调用/为什么要使用erb.js?

时间:2016-10-10 07:36:31

标签: javascript jquery ruby-on-rails ajax ruby-on-rails-4

过去几天我花了很多时间来了解AJAX的不同方面。在阅读了一些介绍后,我设法了解了rails内置的UJS功能。我写的一个小玩具应用程序的例子,我想介绍一些AJAX功能...

控制器操作如下所示

class ExpenseListsController < ApplicationController
  before_action :require_authentication

  ...

  def create
    @expense_list = ExpenseList.new(expense_list_params)
    if @expense_list.save
      respond_to do |format|
        format.html do
          flash[:success] = 'Created!'
          render :show
        end
        format.js
      end
    else
      respond_to do |format|
        format.html do
          @errors = @expense_list.errors
          flash[:danger] = 'Something went wrong!'
          render :new
        end
        format.js
      end
    end
  end

  ...

end

在我看来,我通过remote: true选项

调用该操作

相应的create.js.erb看起来像这样

var form_field = $('.expense_lists_form');
var expenseLists = $('#expense-lists');

expenseLists.append("<%= j render @expense_list %>");
form_field.slideUp(200);

@expense_list的模板如下所示

.col-xs-12.col-lg-3.col-md-4{id: "expense_list_#{expense_list.id}"}
  .panel.panel-default
    .panel-heading
      = link_to expense_list.name, expense_list_path(expense_list)
    .panel-body
      .links
        = link_to 'Modify list', edit_expense_list_path(expense_list), remote: true
        = link_to 'Delete list', expense_list_path(expense_list), method: 'delete', remote: true
      .description
      %p
      - if expense_list.description.present?
        = expense_list.description
      - else
        %i
          No description supplied, add one
          =link_to 'here', edit_expense_list_path(expense_list)
      .email-notification.text-muted
        (Email notifications enabled)
    .panel-footer
      = "Expenses in #{current_month_name}:"
      %b
        = "#{expense_list.sum_of_exp_in_month(current_month, current_year)}€"
      = "(#{expense_list.euros_left_in_month(current_month, current_year)}€ left)" if expense_list.budget_in_euro

这对我有用,但这个想法似乎有一些缺点:

  • 通过额外的* .js.erb文件
  • 来扩展我的文件结构
  • 扭曲了JS与其他代码库的物理分离
  • 当我使用HAML时,它引入了一种新的编码风格(ERB)

现在我有两个问题:

  1. 每个教程(我到目前为止看到过)似乎都在推动这种在Rails中处理AJAX响应的解决方案:为什么?当我检查其他更大的rails项目(例如Diaspora)的代码时,我似乎没有发现它们这样做 - 大多数它们似乎通过$.ajax({ ... })在普通的JS / jQuery中处理它。那么rails-internal UJS方法的主要优点是什么?

  2. 如果出于某种原因,首选UJS-way导轨:您如何组织代码?为*.js.erb - 文件创建额外的目录?

  3. 将所有这些内容转移到位于我的/app/assets/javascript目录中的普通javascript文件并在jQuery中处理AJAX请求会有什么好处?我的控制器响应如何才能响应HTML的适当部分来通过JS更新DOM?换句话说:我怎样才能回答我在Plain Javascript / jQuery中可以处理的部分内容?

  4. 提前致谢! 岸堤

1 个答案:

答案 0 :(得分:1)

那么轨道内部UJS方法的主要优点是什么?

js.erb是一种穷人单页架构(SPA)的形式。

它使得从控制器返回.js响应变得非常容易,这些响应修改当前页面并允许您使用rails帮助程序进行模板化,这样您就不必使用客户端模板系统,例如车把。

请注意,这不是rails内部的内容。 jQuery UJS简单使用rails可以返回多种格式的资源这一事实。你可以将它用于任何可以提供javascript的MVC框架。

主要优点是非常平易近人。 它足以满足经典同步应用程序的需求,这些应用程序在这里和那里都需要少量的ajax。

它让那些认为jQuery.load和脚本标签无处不在的开发人员是最好的事情,因为切片面包只需要足够的绳索就可以自行悬挂。

缺点

  • 违反REST,因为js.erb视图通常用作操作当前页面的过程。
  • js.erb视图中的javascript在按请求提供服务时不会被资产管道缩小。
  • 这会导致糟糕的架构决策。

替代方案是什么?

jquery-ujs进入场景之前很久,我们已经发现执行ajax请求的最佳方法是JSON。

因此,如果您想以异步方式发送表单,则可以执行以下操作:

$(document).on('submit', '.ajax-form', function(e){
  e.preventDefault();
  var $form = $(this);
  var promise = $.ajax($form.attr('action'), {
    accepts: { json: 'application/json' },
    data: $form.serialize(),
    context: $form,
    method: $form.attr('method')
  });
  promise.done(function(response){
    // handle the response
  });
});

这样,javascript逻辑可以连接成一个文件,并在javascript测试工具中单独测试。

您的后端服务器只响应简单数据,并不关心客户端使用它做什么。

但是,这确实需要您在客户端设置某种模板来处理将JSON转换为HTML,并且您需要设置数据绑定之类的东西以使您的表单显示错误。这会导致代码重复。

这就是像Ember和Angular这样的SPA框架进入图片的过程,它可以在客户端进行所有模板化和渲染。

我如何回答我可以在Plain Javascript / jQuery中处理的部分内容?

您可以创建添加控制器响应的其他格式。例如,您可以注册"text/html-partial" mime类型。

或创建其他路线甚至使用查询参数(颤抖)。

然而,由于与js.erb完全相同的原因,这不太理想 - 它导致了一个糟糕的API,因为您的控制器将变为进程而不是面向资源。您最终会创建荒谬的控制器操作,只是为了将html片段传递回客户端。