Reb*_*ele 8 javascript model-view-controller ruby-on-rails ember.js
虽然我最近的大部分工作主要是使用Ruby on Rails和大量的Javascript(主要是jQuery),但我想构建一个单页应用程序,并意识到Ember.js似乎是一个崭露头角的流行框架接近这些应用程序.
从文档和教程的各种来源来看,似乎Ember.js需要一种与Ruby on Rails或其他典型服务器端框架相比如何解决问题的非常不同的思考方式.似乎有可能使用像Ruby on Rails这样的框架随着时间的推移开发的"事物应该如何运作"的某些假设甚至可能妨碍真正理解和拥抱"Ember Way".
在尝试学习Ember时,Ruby on Rails开发人员需要消除哪些先入为主的观念?Ruby on Rails开发人员应该尝试将他/她的思想包裹起来,最具创新性和最重要的Ember概念是什么?
提前致谢!
emk*_*emk 13
我将尽力通过列出Ember和Rails之间的一些主要技术差异,在StackOverflow的精神内回答这个问题.我将在programmers.stackexchange.com上为其他人留下更多的哲学方面.
您可以在工作的jsFiddle中找到下面的所有代码示例,如果这有助于您可视化所有内容的组合方式.
Ember和Rails之间的一个主要区别是收集路由(管理对象列表)和项路由(管理单个对象)之间的关系.在Rails中,这些都由单个资源控制器处理.在Ember中,这些通常由两个不同的路径处理,因为它们操纵两个不同的数据结构:
App.Router.map(function () {
this.route("posts", { path: "posts" });
this.route("post", { path: "post/:post_id" });
});
App.PostsRoute = Ember.Route.extend({
model: function (params) {
return App.Post.find();
}
});
App.PostRoute = Ember.Route.extend({
model: function (params) {
return App.Post.find(params.post_id);
}
});
Run Code Online (Sandbox Code Playgroud)
在Rails中,您的代码分为三大类:
在恩伯,责任的细分是截然不同的.
楷模.Ember模型的工作方式与Rails模型非常相似.
App.Post = DS.Model.extend({
title: DS.attr("string"),
body: DS.attr("string"),
comments: DS.hasMany("App.Comment")
});
Run Code Online (Sandbox Code Playgroud)
路线.路线表示应用中用户可见的位置,它们对应于/post/7
或等的网址/about
.正如您在上面的代码示例中所看到的,路由在Ember中做了很多.最重要的是,他们查找与给定URL对应的模型.正如您将在一秒钟内看到的那样,他们还负责连接适当的控制器和视图.
控制器.控制器与Rails完全不同!关于Ember控制器的两个最重要的事情是:(1)它们基本上是模型对象周围的智能代理,(2)它们通常是单例.因此,您只需PostController
要将其连接到您正在查看的任何帖子.
一般来说,您使用Ember控制器来管理不属于URL或数据库的瞬态.这是一个例子:
App.PostController = Ember.ObjectController.extend({
// This shared between all posts for as long as the app runs (because
// this controller is a singleton), but it doesn't get saved in the database
// (because this is a controller, not a model).
lowRatedCommentsShown: false,
// Called by PostView or its template in response to an HTML event.
showLowRatedComments: function () {
this.set("lowRatedCommentsShown", true);
},
// Called by PostView or its template in response to an HTML event.
hideLowRatedComments: function () {
this.set("lowRatedCommentsShown", false);
}
});
Run Code Online (Sandbox Code Playgroud)
因为Ember控制器是模型周围的代理,它们也倾向于积累几乎属于模型的逻辑,但感觉与应用程序中的特定屏幕紧密相关.
视图和模板.Ember视图和模板一起工作.最好将它们视为GUI小部件.
App.PostView = Ember.View.extend({
// This can be omitted when we're created by a route.
templateName: 'post'
// Any HTML event handlers would go here if we needed them. Our job is to
// map between HTML events and events understood by the controller.
//doubleClick: function (evt) {
// // We'll actually bind this to a specific button, not a click event.
// this.get("controller").send("showLowRatedComments");
//}
});
Run Code Online (Sandbox Code Playgroud)
我们的帖子模板可以自由混合模型定义的字段和控制器定义的字段:
<script type="text/x-handlebars" data-template-name="post">
<h2>{{title}}</h2>
<div class="body">{{body}}</div>
{{#if lowRatedCommentsShown}}
<button {{action 'hideLowRatedComments'}}>Hide Low-Rated Comments</button>
{{else}}
<button {{action 'showLowRatedComments'}}>Show Low-Rated Comments</button>
{{/if}}
{{partial "comments"}}
</script>
Run Code Online (Sandbox Code Playgroud)
请注意,当我们的模型或控制器上的字段发生更改时,视图将自动重新呈现需要更新的HTML部分!
因为Ember.js在浏览器中运行,所以许多操作都是异步的.Ember的许多基本设计都基于使异步更新变得轻松愉快.这种情况的一个关键因素是对象异步加载.当你打电话时find
,你会得到一个卸载的对象:
post = App.Post.find(params.post_id)
post.get("isLoaded"); // -> false
post.get("title"); // -> not yet available
Run Code Online (Sandbox Code Playgroud)
当服务器向您发送数据时,您将看到:
post.get("isLoaded"); // -> true
post.get("title"); // -> "Post #1"
Run Code Online (Sandbox Code Playgroud)
为了帮助实现这一目标,Ember非常依赖于计算属性,观察者和绑定.在每种情况下,关键的想法是数据的更改应该自动波及整个系统.例如,我们可以使用计算属性来确保isLowRated
在注释rating
更改时更新:
App.Comment = DS.Model.extend({
post: DS.belongsTo("App.Post"),
body: DS.attr("string"),
rating: DS.attr("number"),
isLowRated: function () {
return this.get("rating") < 2;
}.property("rating") // A list of properties we depend on.
});
Run Code Online (Sandbox Code Playgroud)
请注意,Ember的Handlebars模板与此系统深度集成.{{title}}
在模板中编写时,您将建立一个绑定,以便在title
更改时自动更新DOM .在编辑字段的情况下,此绑定在两个方向上都有效!对显示值的更改将直接推送回模型(尽管可以使用事务将其回滚).
还值得记住的是,许多动态更新 - 特别是绑定 - 在当前"运行循环"结束时异步运行.这就是为什么你经常会看到Ember.run
测试套件中的调用:
Ember.run(function () {
// Change some bindings here. Not all changes will propagate immediately.
});
// Test that the values have all propagated here, after the run loop is done.
Run Code Online (Sandbox Code Playgroud)
在实践中,Ember感觉比Rails更异步,但是比Node.js这样的事件系统更少异步.这是因为大多数异步更新都是通过绑定自动管理的.
这是我将从严格的技术细节中偏离并提及一些实用建议的地方.Ember Data提供DS.Model
,如上所示.它不是Ember.js的唯一模型层 - 检查ember-rest,ember-resource和类似的替代库.目前还没有正式发布的Ember Data,但是如果你想生活在最前沿,它可以非常谨慎地用于生产应用程序.一些技巧:
hasMany
在序列化对象时为Rails中的每个关系序列化完整的ID列表.如果您正在使用Rails,请参阅active_model_serializers.使用Ember Data可以获得非常好的结果.但它远不如ActiveModel成熟,它需要被视为这样.