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

How to respond_to AJAX call without erb.js / why use erb.js?

本文关键字:js erb 为什么 调用 何响应 响应 AJAX      更新时间:2023-09-26

最近几天我一直在尝试理解rails上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内部UJS方法的主要优点是什么呢?

  2. 如果由于某种原因rails的ujs方式更受欢迎:你如何组织你的代码?为*.js.erb -文件创建额外的目录?

  3. 将所有这些东西转移到位于我的/app/assets/javascript目录的纯javascript文件,并处理jQuery中的AJAX请求,这将是一个很好的做法?我的控制器响应如何看起来像为了响应HTML的适当部分,通过JS更新DOM ?换句话说:我如何用我可以在纯Javascript/jQuery中处理的部分来响应?

提前感谢!安迪

那么rails-内部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框架出现的地方,它们在客户端完成所有的模板和渲染。

我怎么能与部分,我可以在纯Javascript/jQuery处理响应?

你可以创建额外的格式,你的控制器响应。例如,您可以注册一个"text/html-partial" mime类型。

或者创建额外的路由,甚至使用查询参数(颤栗)。

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