【问题标题】:Is it correct to have files that mix Javascript and ruby? ie. (.js.erb)?拥有混合 Javascript 和 ruby​​ 的文件是否正确? IE。 (.js.erb)?
【发布时间】:2011-11-05 12:30:15
【问题描述】:

我最近读到在 JavaScript 中嵌入 ruby​​ 并不是一个好主意。 然而,在诸如 David Heinemeier Hansson 的 Agile Web Development with Rails 等书籍中,这正是它所做的。 如果用 JS 嵌入 ruby​​ 不是一个好主意,那么 这种情况的最佳做法是什么? 给定这样简单的东西:(jQuery + ruby​​)

posts_controller

def create
  @post = Post.new(params[:post])
    respond_to do |format|
      if @post.save
        format.html { redirect_to(@post, :notice => 'Post was successfully created.') }
        format.js #will use this response to process ajax
      else
        format.html { render :action => "new" }
      end
    end
end

create.js.erb

$tr = $('<tr>');
$td1 = $('<td>').text('<%= @post.title %>');  
$td2 = $('<td>').text('<%= @post.content %>');
$tr.append($td1, $td2);
$('table tbody').append($tr);

应该如何重构以遵循不将 ruby​​ 嵌入 JS 的“最佳实践”?(如果是这样的话)

我真的需要对此有所启发,并且可能要正确理解这些概念,因为我已经读过 Rails 3.1 将通过资产将 JS 与 Ruby 完全分开?(这是正确的吗?

谢谢!

【问题讨论】:

  • 您阅读了哪个版本的Agile Web Development with Rails?请记住,Rails 的每个新版本都有本书的相应版本(Rails 3 的第 4 版:pragprog.com/book/rails4/agile-web-development-with-rails
  • 我当然读过第四版。它仍然使用 rjs 模板,但没有 jQuery;取而代之的是 rails 3.0 的默认 JS 框架

标签: javascript jquery ruby-on-rails ruby


【解决方案1】:

是的,你可以写,但文件扩展名应该是

“.js.erb”

【讨论】:

    【解决方案2】:

    RJS 模板本质上是长期以来的工作方式,这就是为什么您仍然会在教程中看到该技术如此流行的原因。话虽如此,正如您所注意到的,他们正在退出,而且有充分的理由。

    我确信 RJS 模板是一件非常糟糕的事情的原因有很多,但一个重要的原因是它们将您的视图 JS 与您的视图 HTML 耦合的紧密程度.许多问题由此产生,其中一些是:

    1. 缺乏灵活性。

      以您的代码为例。如果您希望能够从不同的视图创建帖子怎么办?并有不一样的效果?也许页面上根本没有&lt;table&gt;,而您只想弹出“成功”消息?等等。

      如果您只是想要帖子的数据表示,但您的 javascript 模板是为了操作 HTML 而编写的?

      您如何在一个create.js.erb 中处理所有这些,这很可能与帖子new.html.erb 模板紧密耦合?

    2. 复杂性。

      RJS 模板在某种程度上是在真空中运行的。在服务器端生成,它们的执行不受 DOM 事件的约束。这使得在创建对象后在页面上更新&lt;form&gt; 之类的操作变得很棘手,因为您没有参考框架来在 JS 模板中选择适当的&lt;form&gt;(例如&lt;form id="new_post_123"&gt;) .有一些解决方法,但它们比需要的更复杂。

      通过绑定到一个表单客户端并处理结果,这个问题就被消除了。您无需在回复后找到合适的表格进行更新。

      使用 RJS,您没有这样的绑定,并且您不得不使用 HTML 的已知结构来检索和操作适当的元素。不必要的复杂性的一个例子。


    关于您的问题:

    我真的需要对此有所启发,并且可能要正确理解概念,因为我已经读过 Rails 3.1 将通过资产将 JS 与 Ruby 完全分开?(这是正确的吗?)

    这基本上是正确的。资产管道虽然很酷,但并没有提供任何全新的东西。 Sprockets 和 Sass 等资产框架以及它们支持的工作流程已经存在了一段时间。 Rails 3.1 资产管道只是将它们带入标准实践。正如 DHH 在他最近的RailsConf keynote 中谈到的那样,这更像是一个观点问题。通过为这些资产(尤其是 js 文件)带来更大的组织,让它们感觉更像是一等公民,可以说,与您的后端代码一样值得关注。与public/javascripts 的“垃圾抽屉”感觉相反。


    关于实现:

    您可能会这样做(尽管未经测试且有点简化,例如在 Rails 3 中,您可能会为此使用响应者而不是 respond_to 块:

    # as you have, but returning the object as data which can be handled client-side,
    # rather than RJS generated by the server
    def create
      @post = Post.new(params[:post])
      respond_to do |format|
        if @post.save
          format.js { render :json => @post }
        else
          # ...
        end
      end
    end
    
    // Then in your client side JS, a handler for your remote form.
    $(function(){
      $('#your-create-form').bind('ajax:success', function(data, status, xhr) {
        // simply repeating what you had in the template, replacing the erb with
        // attributes from the returned json
        $tr = $('<tr>');
        $td1 = $('<td>').text(data.title);  
        $td2 = $('<td>').text(data.content);
        $tr.append($td1, $td2);
        $('table tbody').append($tr);
      });
    }
    

    【讨论】:

    • 这看起来不错。具有讽刺意味的是,在我阅读 DHH 的 Rails 敏捷 Web 开发之前,这几乎就是我以前做的事情。所以,如果这是“自然”的做法,我仍然不明白他们为什么决定在框架中包含 .js.erb 文件? (显然是最有效的)我不想在这里令人讨厌,但我认为既然你很好地理解了这个问题,如果你能谈谈这两种方法的优缺点,那就太好了。祝你有美好的一天,再次感谢!
    • 确实如此。恭喜!你的知识渊博!感激不尽!
    【解决方案3】:

    我相信您会发现 PHP 开发人员、Perl、ASP 和任何其他服务器端语言的初学者都会问这个问题。似乎没有太多情况下您希望将 javascript 代码内联。唯一的情况可能是您根据特定情况对其进行自定义,但在我的脑海中我不能想想你需要像这样自定义它的任何情况。

    性能方面,如果您有很多 javascript 并且将其全部包含在输出中,那么您的页面就会膨胀。如果您要添加一个大型应用程序,一个 1k 的页面将变成一个 >100k 的页面。此外,缓存该信息可能会更加困难,因为如果用户已登录,或者当天是否有特殊广告等。您最好将其拆分到自己的文件中,以便您也可以“最小化”它 (http://en.wikipedia.org/wiki/Minification_%28programming%29)。

    从开发人员到开发人员,我可以给您讲述在 PHP 和 Smarty 模板中嵌入 javascript(和 html)的恐怖故事。善待与您合作的任何人,并将所有语言拆分成各自的文件。假设您正在与 Bob 一起工作,他是一个很棒的 javascript 人.. 但对应用程序以及它如何吐出代码一无所知。由于应用程序缺乏单点真实性,在 erb 中散布 javascript 会令人沮丧 - 如果他想调整某些东西,他将查看你所有的 erb 以确定他必须放在哪里它或它最初在哪里。您真的希望对您的后端结构知之甚少的人浏览这些文件吗?

    虽然有几种情况您希望将 bootstrap 数据放入其中。如果您在启动时有大量数据要注入页面,请将其分配给页面启动时的几个变量比在每次页面加载时发出 ajax 请求更高效。

    请对我们这些前端人员好点,除非你有一个真正好的理由.. 将 JS 保存在单独的文件中 :)

    编辑:这是一个做你想做的事(我认为)的例子,没有真正使用模板化的 javascript:

    app.js:

    postUpdater = function (data) {
        $tr = $('<tr>');
        $td1 = $('<td>').text(data.title);  
        $td2 = $('<td>').text(data.content);
        $tr.append($td1, $td2);
        $('table tbody').append($tr);
    };
    
    $("#save_button").click(function () {
        $.post('/save/ur/', {the:data}, postUpdater);
    });
    

    在 ruby​​ 中,您只想将 @post 渲染为 json。我认为它实际上是 @post.to_json,但您可能必须 require 'json' 才能使其工作。不过,这可能会让你更快地到达那里:output formated json with rails 3(我不是真正的红宝石人..我们只是在我工作的公司使用它,所以我当然一直在接受它)

    现在,关于为什么不只输出模板化的 javascript 文件的理论。假设您在保存该 javascript 文件时需要处理一大堆事情。这意味着您必须在该 ajax 请求上输出大量内容并执行它。您将通过互联网推送更大的文件(稍微慢一点),并且可能不得不“评估”响应(评估是邪恶的)。所以,这是一件坏事。另一个可能不好的事情是您无法访问您调用保存的位置。所以,如果我有这个观点..

    new PostViewer({
        savePost: function () {
            var self = this;
            $.post('/save/url/', {the:data}, function (response) {
                self.trigger('saveSuccessful', response);
            });
        }
    });
    

    当 savePost 被调用时,简单地告诉视图“嘿,保存成功!”将更加困难(可能不会引入大量黑客)。

    希望这对您正在寻找的目标更加准确。

    【讨论】:

    • 这有点偏离目标,因为这个问题的标题可能有点偏离目标。他并没有真正问将 javascript 内联到 HTML 中是否是一个好主意,但如果完整的 javascript 模板是一个好的做法,如果不是,还有什么替代方案?
    • 我自己说得再好不过了。我需要知道作为 Rails 中嵌入 JavaScript(.js.erb 文件)中的 ruby​​ 的替代方法,最佳实践是什么。一些带有代码的示例将非常有帮助!此外,为什么或为什么不使用 .js.erb 文件的理论原因也很棒!谢谢你们!
    • 是的,实际上,这更符合我的要求。在 rails 中输出 json 很容易。另一方面,我有点迷失了 PostViewer 示例,因为您将其称为视图。 [我的JS没那么强:(]谢谢你的详细回复!
    • 好吧,当你的 git 稍微好一点时,你就会明白我在说什么了 :) 只是需要时间,但我希望你不会犯我犯的所有错误。去查找 Douglas Crockford .. 他有一些非常好的材料(特别是“The Good Parts”)以获得一些深入的 JS 信息。他有点.. 狂热.. 有时(即 i++ 被认为是坏事?)但他有一些很好的例子和解释。
    【解决方案4】:

    如果您在 JavaScript 文件中嵌入动态数据,那么您通常必须为其提供适合经常变化的内容的缓存规则。

    如果您需要使用 JS 处理动态内容,那么通常最好有一个静态的、可缓存的、可重用的脚本来从其他地方获取数据。

    在这个具体的例子中,虽然我不确定,因为没有很多上下文,但看起来你最好直接生成 HTML,而不是生成生成 HTML 的 JS。

    【讨论】:

    • 上面的例子是一个过于简单的博客文章例子。或者像我现在使用的那样添加评论。 (即。提交表单并在同一个视图上呈现 Ajax 响应。)那么,您提到的可重用脚本的示例是什么?感谢您的回复。
    • 将所有代码移动到一个函数中,让 Ajax 响应为 { "title": "foo", "content": "bar" },然后让成功处理程序调用传入该数据的函数。
    • 我理解这部分。现在..你能告诉我如何修改控制器代码以使用这样的功能吗?再次感谢。
    • 我不熟悉 Rails 输出 JSON 的最佳实践。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 2011-03-02
    • 1970-01-01
    • 2016-02-27
    • 2013-09-16
    • 2010-10-12
    相关资源
    最近更新 更多