拥有混合Javascript和ruby的文件是否正确? 即。 (.js.erb)?

我最近读到在JavaScript中嵌入ruby 并不是一个好主意。 然而,在诸如David Heinemeier Hansson的带有Rails的敏捷Web开发之类的书中,这正是它所做的。 如果用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 = $(''); $td1 = $('').text(''); $td2 = $('').text(''); $tr.append($td1, $td2); $('table tbody').append($tr); 

应该如何重构以遵循不用JS嵌入ruby的“最佳实践”?(如果是这种情况)

我真的需要对此有所启发,也许正确的理念是因为我已经读过rails 3.1将JS完全通过资产从Ruby中分离出来?( 这是正确的吗?

谢谢 !

RJS模板基本上是长时间完成工作的方式,这就是为什么你仍然会在教程中看到这种技术的流行。 话虽这么说,正如你所注意到的那样,他们正在走出去,并且有充分的理由。

我确信有很多原因可以解释为什么RJS模板是一件非常糟糕的事情 ,但重要的是它们将您的视图JS与视图HTML结合起来的紧密程度。 由此产生了许多问题,其中一些是:

  1. 缺乏灵活性。

    以您的代码为例。 如果您希望能够从其他视图创建post,该怎么办? 并有不同的效果? 也许页面上根本没有

    ,你只想弹出“成功”消息? 等等。

    如果您只想要发布post的数据表示,但是您的javascript模板是为了操纵HTML而编写的,该怎么办?

    你如何在一个create.js.erb处理所有这些,这个post与postnew.html.erb模板紧密相连?

  2. 复杂。

    RJS模板在某种程度上真空运行。 在服务器端生成,它们的执行不受DOM事件的约束。 这使得在创建对象之后执行诸如更新页面上的

    类的操作变得棘手,因为您没有参考框架来在JS模板中选择适当的

    (例如

    )。 有解决方法,但它们比它们需要的更复杂。

    通过绑定到客户端表单并处理结果,可以消除此问题。 您无需在响应后找到要更新的正确表单。

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


关于你的问题:

我真的需要对此有所启发,也许正确的理念是因为我已经读过rails 3.1将JS完全通过资产从Ruby中分离出来?(这是正确的吗?)

这基本上是正确的。 资产管道虽然很酷,却没有提供任何全新的产品。 Sprockets和Sass等资产框架及其启用的工作流程已经存在了一段时间。 Rails 3.1资产管道只是将它们引入标准实践。 正如DHH在他最近的RailsConf主题演讲中谈到的那样,这更像是一个透视问题。 通过为这些资产提供更大的组织,特别是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 = $(''); $td1 = $('').text(data.title); $td2 = $('').text(data.content); $tr.append($td1, $td2); $('table tbody').append($tr); }); } 

如果您在JavaScript文件中嵌入动态数据,那么您通常必须为其提供适用于可能经常更改的内容的缓存规则。

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

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

我相信你可以通过开始PHP开发,Perl,ASP和其他任何服务器端语言来找到这个问题。 似乎没有太多的情况你想要你的javascript代码内联..唯一的可能是你在某个特定情况下定制它的地方,但我不能在我的头顶想想你需要像那样定制它的任何情况。

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

从开发人员到开发人员,我可以为您提供在PHP和Smarty模板中嵌入javascript(和html)的恐怖故事。 对你工作的任何人都要好,并将所有语言分成他们自己的文件。 假设你正在与Bob合作,他是一个很棒的javascript家伙……但是对于应用程序及其如何吐出代码并不了解。 由于缺乏应用程序的单点事实,在erb中使用javascript会令人沮丧 – 如果他想要调整某些内容,他将会查看你所有的错误以确定他必须放在哪里它或它原来在哪里。 你真的想要一个对你的后端结构知之甚少的人来浏览这些文件吗?

有几种情况虽然你想把bootstrap数据放在哪里..如果你有很多数据要在启动时注入页面,那么在页面启动时分配给几个变量的性能比在每个页面加载时出去并发出ajax请求。

请高兴我们前端的人,除非你有一个真正的理由……将JS保存在单独的文件中:)

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

app.js:

 postUpdater = function (data) { $tr = $(''); $td1 = $('').text(data.title); $td2 = $('').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'才能使它工作。 这可能会让你更快到达: 输出格式json与rails 3 (我不是真正的ruby家伙……我们只是在我工作的公司使用它,所以当然我一直在捡起它)

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

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

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

希望对你所寻找的东西有更多的目标。