【问题标题】:How to respond_to AJAX call without erb.js / why use erb.js?如何在没有 erb.js 的情况下响应 AJAX 调用/为什么使用 erb.js?
【发布时间】:2017-02-18 14:00:57
【问题描述】:

最近几天我一直在尝试了解 AJAX on rails 的不同方面。在阅读了一些介绍之后,我设法了解了 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-files 创建额外的目录?

  3. 将所有这些内容传输到位于我的/app/assets/javascript 目录中的纯javascript 文件并在那里处理jQuery 中的AJAX 请求是一个好的做法?为了响应 HTML 的适当部分以通过 JS 更新 DOM,我的控制器响应应该是什么样子?换句话说:我怎样才能用纯 Javascript/jQuery 处理的部分响应?

提前致谢! 安迪

【问题讨论】:

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


    【解决方案1】:

    那么,rails-internal UJS 方法的主要优势是什么?

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

    它可以很容易地从控制器返回 .js 响应,这些响应会修改当前页面,并允许您使用 rails 帮助器进行模板化,这样您就不必使用客户端模板系统,例如把手。

    请注意,这并不是真正的 Rails 内部。 jQuery UJS simple 使用了 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 片段传回客户端。

    【讨论】:

    • 好的,非常感谢您对此的意见。听起来好像要么我必须忍受可怕的架构决策(这些具体是什么?),要么使用像 Angular 这样的框架来处理模板,我是否理解你的正确?是否可以通过 mustache.js 之类的库以更少的开销实现模板化?
    • .js.erb 的糟糕架构设计常常导致您远离 RESTful 构建并进入 do_foo_to_bar 风格的远程过程调用汤。没有明确的职责分离,随着复杂程度的增加,您的 javascript 变得非常难以遵循,因为流程遍布各处。它基本上就像有一堆脚本标签。除了脚本标签中包含巨大的 HTML 字符串。
    • 这不是 JS.erb 和“全栈”SPA 之间的非黑即白的决定——如果你只需要 ajax 来实现其他“经典”应用程序中的某些功能——你可以很好地构建一个更轻的堆栈在车把上用于模板和主干用于数据绑定。
    • 您甚至可以只使用下划线/lodash .template 或使用 jQuery 构建节点树。这完全取决于您的要求。
    • 问题是:我不太确定我的要求。到目前为止,我认为这个小项目是一个玩具应用程序,但谁知道它会变得多大(我有一些想法......)。但是你所说的关于流量的传播。不过,我想知道为什么每个人都在推广.js.erb 设计(顺便说一句:有没有技术术语?)而不是其他?是因为介绍性文章的性质,通常只涉及玩具应用程序吗?
    猜你喜欢
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多