课程表

Meteor课程

工具箱
速查手册

Meteor 编辑帖子

当前位置:免费教程 » JS/JS库/框架 » Meteor

上一章,我们已经学会了创建帖子,下面来学习编辑和删除它们。页面的代码非常简单,让我们在这个时候来谈论一下 Meteor 是如何管理用户权限。

让我们先设置我们的路由器,添加一个可以访问帖子编辑页的路径,并设置它的数据上下文:

  1. Router.configure({
  2. layoutTemplate: 'layout',
  3. loadingTemplate: 'loading',
  4. notFoundTemplate: 'notFound',
  5. waitOn: function() { return Meteor.subscribe('posts'); }
  6. });
  7. Router.route('/', {name: 'postsList'});
  8. Router.route('/posts/:_id', {
  9. name: 'postPage',
  10. data: function() { return Posts.findOne(this.params._id); }
  11. });
  12. Router.route('/posts/:_id/edit', {
  13. name: 'postEdit',
  14. data: function() { return Posts.findOne(this.params._id); }
  15. });
  16. Router.route('/submit', {name: 'postSubmit'});
  17. var requireLogin = function() {
  18. if (! Meteor.user()) {
  19. if (Meteor.loggingIn()) {
  20. this.render(this.loadingTemplate);
  21. } else {
  22. this.render('accessDenied');
  23. }
  24. } else {
  25. this.next();
  26. }
  27. }
  28. Router.onBeforeAction('dataNotFound', {only: 'postPage'});
  29. Router.onBeforeAction(requireLogin, {only: 'postSubmit'});

帖子编辑模板

我们可以现在专注模板了。我们的 postEdit 模板就包含一个相当标准的表单:

  1. <template name="postEdit">
  2. <form class="main form">
  3. <div class="form-group">
  4. <label class="control-label" for="url">URL</label>
  5. <div class="controls">
  6. <input name="url" id="url" type="text" value="{{url}}" placeholder="Your URL" class="form-control"/>
  7. </div>
  8. </div>
  9. <div class="form-group">
  10. <label class="control-label" for="title">Title</label>
  11. <div class="controls">
  12. <input name="title" id="title" type="text" value="{{title}}" placeholder="Name your post" class="form-control"/>
  13. </div>
  14. </div>
  15. <input type="submit" value="Submit" class="btn btn-primary submit"/>
  16. <hr/>
  17. <a class="btn btn-danger delete" href="#">Delete post</a>
  18. </form>
  19. </template>

post_edit.js 来配合这个的模板:

  1. Template.postEdit.events({
  2. 'submit form': function(e) {
  3. e.preventDefault();
  4. var currentPostId = this._id;
  5. var postProperties = {
  6. url: $(e.target).find('[name=url]').val(),
  7. title: $(e.target).find('[name=title]').val()
  8. }
  9. Posts.update(currentPostId, {$set: postProperties}, function(error) {
  10. if (error) {
  11. // 向用户显示错误信息
  12. alert(error.reason);
  13. } else {
  14. Router.go('postPage', {_id: currentPostId});
  15. }
  16. });
  17. },
  18. 'click .delete': function(e) {
  19. e.preventDefault();
  20. if (confirm("Delete this post?")) {
  21. var currentPostId = this._id;
  22. Posts.remove(currentPostId);
  23. Router.go('postsList');
  24. }
  25. }
  26. });

相信你现在已经对这些代码都相当的熟悉了。

我们有两个事件回调函数:一个用于表单的 submit 事件,一个用于删除链接的 click 事件。

删除链接的回调函数是非常简单的:先防止默认点击事件,然后提示确认窗口。如果确认删除,它将从模板的数据上下文中获得当前帖子的 ID ,然后删除它,最后把用户重定向到主页。

更新的回调函数需要长一点时间,但并不复杂。在防止默认提交事件然后获取了当前帖子之后,我们将从表单中获取相关字段的值,并将它们存储在一个 postProperties 的对象中。

然后,我们把该对象通过 $set 操作符(只更新指定字段的值,保留其他字段的值)传递给 Meteor 的 Collection.update() 方法,并通过回调函数去判断如果更新失败就显示错误信息;如果更新成功了,将自动返回到该帖子的页面。

添加链接

我们还应该添加一个编辑帖子的链接,以便用户可以访问到帖子编辑页面:

  1. <template name="postItem">
  2. <div class="post">
  3. <div class="post-content">
  4. <h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
  5. <p>
  6. submitted by {{author}}
  7. {{#if ownPost}}<a href="{{pathFor 'postEdit'}}">Edit</a>{{/if}}
  8. </p>
  9. </div>
  10. <a href="{{pathFor 'postPage'}}" class="discuss btn btn-default">Discuss</a>
  11. </div>
  12. </template>

当然,我们不能让你的帖子提供给其他用户去编辑。这就要通过 ownPost helper 来帮忙:

  1. Template.postItem.helpers({
  2. ownPost: function() {
  3. return this.userId === Meteor.userId();
  4. },
  5. domain: function() {
  6. var a = document.createElement('a');
  7. a.href = this.url;
  8. return a.hostname;
  9. }
  10. });

我们的帖子编辑表单看起来很好,但是目前还不能够进行任何的编辑,这是为什么?

设置权限

自从我们移除了 insecure 包,现在所有客户端的修改都会被拒绝。

为了解决这个问题,我们需要建立一些权限规则。首先,在 lib 目录下创建一个新的 permissions.js 文件。这样做将会首先加载我们权限文件(它在服务端和客户端都可以被加载到):

  1. // check that the userId specified owns the documents
  2. ownsDocument = function(userId, doc) {
  3. return doc && doc.userId === userId;
  4. }

在创建帖子这个章节,我们抛弃了 allow() 方法,因为我们只通过服务端方法去插入新的帖子(绕过了 allow() 方法)。

但是现在我们要在客户端编辑和删除帖子!我们回到 posts.js 文件并添加 allow()

  1. Posts = new Mongo.Collection('posts');
  2. Posts.allow({
  3. update: function(userId, post) { return ownsDocument(userId, post); },
  4. remove: function(userId, post) { return ownsDocument(userId, post); }
  5. });
  6. //...

限制编辑

尽管你可以编辑自己的帖子,但并不意味着你可以允许去编辑帖子的每个属性。例如,我们不允许用户创建一个帖子之后,再将其分配给其他用户。

我们用 Meteor 的 deny() 方法,以确保用户只能编辑特定的字段:

  1. Posts = new Mongo.Collection('posts');
  2. Posts.allow({
  3. update: function(userId, post) { return ownsDocument(userId, post); },
  4. remove: function(userId, post) { return ownsDocument(userId, post); }
  5. });
  6. Posts.deny({
  7. update: function(userId, post, fieldNames) {
  8. // 只能更改如下两个字段:
  9. return (_.without(fieldNames, 'url', 'title').length > 0);
  10. }
  11. });
  12. //...

代码中的 fieldNames 数组,它包含了需要被修改的字段,并使用 Underscorewithout() 方法返回一个不包含 urltitle 字段的子数组。

正常情况下,这个数组应该是空的,它的长度应该是0。如果有人采取其他操作,这个数组的长度将变为1或更多,回调函数将返回 true (因此禁止更新)。

你也许注意到了在我们的代码中没有检查链接是否重复的代码。这就意味着用户成功添加一个链接后,再编辑时就会绕过检查。这个问题同样可以通过为编辑帖子表单使用 Meteor 内置方法来解决,但是我们将它作为练习留给读者。

内置方法的回调 vs 客户端数据操作

创建帖子,我们使用的是 postInsert 的内置方法,而编辑和删除帖子,我们直接在客户端调用 updateremove,并通过 allowdeny 去限制使用权限。

我们该如何去选择使用呢?

当操作相对比较直观,你可以通过 allowdeny 去设置你的规则的时候,直接在客户端进行操作通常会更简单。

然而,一旦你需要做一些在用户控制以外的事情(比如设置一个新帖子的时间戳,或者把帖子分配到正确的用户),这种情况使用内置方法会更好。

内置方法也适用在其他的一些情景:

  • 当你需要通过内置方法的回调函数去获得返回值的时候,而不是等待响应和同步才传递的数据。
  • 对于一些繁重的数据库操作,比如要提取大量的数据集合。
  • 计算或者合计数据的时候(比如:计数、平均值、求和)。

请阅读我们的 blog 来深入了解这个话题。

转载本站内容时,请务必注明来自W3xue,违者必究。
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号