简体   繁体   English

如何在没有erb.js的情况下响应AJAX调用/为什么使用erb.js?

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

The last few days I've spent trying to understand different facets of AJAX on rails. 最近几天,我花了很多时间来理解AJAX在轨道上的不同方面。 After reading some introductions I've managed to get an idea of the rails built-in UJS feature. 在阅读了一些介绍之后,我设法了解了Rails内置的UJS功能。 An example from a small toy app I wrote and where I want to introduce some AJAX-capability... 我编写的一个小型玩具应用程序中的一个示例,我想在其中介绍一些AJAX功能...

The controller action looks as follows 控制器动作如下

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

In my view I call the action via the remote: true option 在我看来,我是通过remote: true选项调用该操作的

The respective create.js.erb looks like this 各自的create.js.erb看起来像这样

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

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

The template for @expense_list looks like this @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

It works but to me this idea seems to have some down-sides: 它可行,但是对我来说,这个想法似乎有一些缺点:

  • Bloats my file structure by having extra *.js.erb files 通过拥有额外的* .js.erb文件来膨胀我的文件结构
  • Distorts the physical separation of JS and the rest of the codebase 扭曲JS与其余代码库的物理分离
  • As I use HAML it introduces a new style of coding (ERB) 当我使用HAML时,它引入了一种新的编码方式(ERB)

Now I have two questions: 现在我有两个问题:

  1. Every tutorial (I've seen so far) seems to promote this kind of solution for handling AJAX responses in Rails: Why? 每个教程(到目前为止,我都看过)似乎都在推广这种在Rails中处理AJAX响应的解决方案:为什么? When I check the code of other, larger rails projects (eg Diaspora) I do not seem to find them do it this way - most of them seem to handle it inside plain JS/jQuery via $.ajax({ ... }) . 当我检查其他较大的Rails项目(例如Diaspora)的代码时,我似乎没有发现它们是这样做的-大多数对象似乎都通过$.ajax({ ... })在纯JS / jQuery中处理它$.ajax({ ... }) So what would be the major advantages of the rails-internal UJS approach? 那么,内部使用Rails的UJS方法的主要优点是什么?

  2. If the rails UJS-way is preferrable for some reason: How do you organise your code? 如果出于某些原因,最好使用Rails UJS-way:如何组织代码? Create extra directories for the *.js.erb -files? *.js.erb -files创建额外的目录吗?

  3. What would be a good practice to transfer all this stuff to plain javascript files located in my /app/assets/javascript directory and handle the AJAX requests within jQuery there? 将所有这些内容传输到我的/app/assets/javascript目录中的纯javascript文件并在jQuery中处理AJAX请求的最佳实践是什么? How would my controller response have to look like in order to respond with the proper portion of HTML to update the DOM with via JS? 为了通过HTML的适当部分进行响应以通过JS更新DOM,我的控制器响应将如何显示? In other words: How can I respond with a partial that I can handle in Plain Javascript/jQuery? 换句话说:我该如何响应我可以在Plain Javascript / jQuery中处理的部分内容?

Thanks in advance! 提前致谢! Andi 和我

So what would be the major advantages of the rails-internal UJS approach? 那么,内部使用Rails的UJS方法的主要优点是什么?

js.erb is a form of a poor mans Single Page Architecture (SPA). js.erb是穷人的单页体系结构(SPA)的一种形式。

It makes it just easy enough to return .js responses from your controller which modify the current page and lets you use the rails helpers for templating so that you don't have to use a client side templating system such as handlebars. 它很容易从控制器返回.js响应,从而修改当前页面,并允许您使用rails helper进行模板制作,因此您不必使用客户端模板制作系统(如把手)。

Note that this is not really internal to rails. 请注意,这并不是Rails真正的内部功能。 jQuery UJS simple uses the fact that rails can return multiple formats of a resource. jQuery UJS简单地使用了Rails可以返回资源的多种格式的事实。 You could potentially use this with any MVC frameworks that can serve javascript. 您可以将其与任何可以使用javascript的MVC框架一起使用。

The main advantage is that it is very approachable. 主要优点是它非常平易近人。 Its just enough for classic syncronous apps that want a few sprinkles of ajax here and there. 对于经典的同步应用程序来说,这足够了,这些应用程序在这里和那里想要少量的Ajax。

It gives developers who think jQuery.load and script tags everywhere is the best thing since sliced bread just enough rope to hang themselves with. 它给那些认为jQuery.load和script标签无处不在的开发人员是最好的选择,因为切成薄片的面包刚好可以用来挂自己。

The cons 缺点

  • Violates REST as js.erb views are usually used as procedures to manipulate the current page. 违反REST的js.erb视图通常用作处理当前页面的过程。
  • the javascript in a js.erb view is not minified by the assets pipeline as it served per request. 资产管道不会缩小js.erb视图中的javascript,因为它按请求提供服务。
  • It leads to horrible architecture decisions. 这导致了可怕的架构决策。

Whats the alternative? 有什么选择?

Long before jquery-ujs entered the scene we had already figured out that the best way to do ajax requests is JSON. jquery-ujs进入现场很久之前,我们就已经知道执行ajax请求的最佳方法是JSON。

So if you want to send a form asynchronously you would do: 因此,如果要异步发送表单,可以这样做:

$(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
  });
});

This way the javascript logic can be concatenated into a single file, and tested separately in javascript testing tools. 这样,可以将javascript逻辑连接到单个文件中,并在javascript测试工具中分别进行测试。

Your backend server just responds with simple data and does not concern itself with what the client does with it. 您的后端服务器仅以简单的数据作为响应,而不关心客户端如何处理它。

However this does require you to setup some sort of templating on the client side to handle converting JSON to HTML and you need to setup stuff like data bindings to have your form display errors. 但是,这确实需要您在客户端上设置某种模板以处理将JSON转换为HTML的过程,并且需要设置诸如数据绑定之类的内容以使表单显示错误。 This leads to code duplication. 这导致代码重复。

This is where SPA frameworks like Ember and Angular come into the picture which do all the templating and rendering in the client. 这是SPA框架(例如Ember和Angular)出现的地方,它们完成了客户端中的所有模板和渲染。

How can I respond with a partial that I can handle in Plain Javascript/jQuery? 我该如何处理我可以在Plain Javascript / jQuery中处理的部分内容?

You could create add additional formats which your controller responds to. 您可以创建其他格式,以供控制器响应。 You could for example register a "text/html-partial" mime type. 例如,您可以注册"text/html-partial" MIME类型。

Or create additional routes or even use a query param (shudder). 或创建其他路由,甚至使用查询参数(抖动)。

However this is less than ideal for the exact same reason as js.erb - it leads to a crappy API as your controllers will become process instead of resource oriented. 但是,由于与js.erb完全相同的原因,这并不理想-它导致API糟糕,因为您的控制器将变为进程而不是面向资源的。 You will end up creating ridiculous controller actions just to pass html fragments back to the client. 您最终将创建荒谬的控制器操作,只是将html片段传递回客户端。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM