Editing Posts

8

翻訳の進捗

本章で学ぶこと:

  • 投稿を編集するフォームを加えます。
  • 編集(permissions?=権限?)をセットアップする。
  • (Restrict which properties can be edited?)
  • これまでで投稿を作ることができたので、次のステップは投稿の編集と削除をできるようにすることです。  そうするための UI コードはとてもシンプルですが、  そろそろ Meteor でユーザーパーミッションを管理する方法を話す良い時期でしょう。

    はじめに、ルーターをつなぎましょう。  私たちは投稿編集ページアクセスするためのルートを加えて、データコンテキストを設定します:

    Router.configure({
      layoutTemplate: 'layout'
    });
    
    Router.map(function() {
      this.route('postsList', {path: '/'});
    
      this.route('postPage', {
        path: '/posts/:_id',
        data: function() { return Posts.findOne(this.params._id); }
      });
    
      this.route('postEdit', {
        path: '/posts/:_id/edit',
        data: function() { return Posts.findOne(this.params._id); }
      });
    
      this.route('postSubmit', {
        path: '/submit'
      });
    });
    
    var requireLogin = function() {
      if (! Meteor.user()) {
        if (Meteor.loggingIn())
          this.render('loading')
        else
          this.render('accessDenied');
    
        this.stop();
      }
    }
    
    Router.before(requireLogin, {only: 'postSubmit'});
    
    lib/router.js

    The Post Edit Template

    これで私たちはテンプレートに集中することができます。  この postEdit テンプレートはスタンダードなフォームです:

    <template name="postEdit">
      <form class="main">
        <div class="control-group">
            <label class="control-label" for="url">URL</label>
            <div class="controls">
                <input name="url" type="text" value="{{url}}" placeholder="Your URL"/>
            </div>
        </div>
    
        <div class="control-group">
            <label class="control-label" for="title">Title</label>
            <div class="controls">
                <input name="title" type="text" value="{{title}}" placeholder="Name your post"/>
            </div>
        </div>
    
        <div class="control-group">
            <div class="controls">
                <input type="submit" value="Submit" class="btn btn-primary submit"/>
            </div>
        </div>
        <hr/>
        <div class="control-group">
            <div class="controls">
                <a class="btn btn-danger delete" href="#">Delete post</a>
            </div>
        </div>
      </form>
    </template>
    
    client/views/posts/post_edit.html

    そしてこれが(goes with it?)するpost_edit.jsマネージャーです。

    Template.postEdit.events({
      'submit form': function(e) {
        e.preventDefault();
    
        var currentPostId = this._id;
    
        var postProperties = {
          url: $(e.target).find('[name=url]').val(),
          title: $(e.target).find('[name=title]').val()
        }
    
        Posts.update(currentPostId, {$set: postProperties}, function(error) {
          if (error) {
            // display the error to the user
            alert(error.reason);
          } else {
            Router.go('postPage', {_id: currentPostId});
          }
        });
      },
    
      'click .delete': function(e) {
        e.preventDefault();
    
        if (confirm("Delete this post?")) {
          var currentPostId = this._id;
          Posts.remove(currentPostId);
          Router.go('postsList');
        }
      }
    });
    
    client/views/posts/post_edit.js

    そろそろ、このコードのほとんどはおなじみになってきたことでしょう。

    私たちは2つのテンプレートのイベントコールバックがあります:  ひとつはフォームの submit イベントで、もうひとつはリンクを削除する click イベントです。

    delete コールバックは、かなりシンプルです:  デフォルトのクリックイベントを抑制して、確認を求めます。  (get it?=これを終えると?)、テンプレートのデータコンテキストから現在の投稿 ID を取得して、  ( it?=現在の投稿ID)を削除して、最終的にユーザーをホームページにリダイレクトします。

    updateコールバックは少し長いですが、それほど複雑ではありません。  デフォルトのイベントを抑制して、現在の投稿を取得した後で、  私たちはページから新しいformフィールドの値を取得して、postProperties オブジェクトに(them?)を格納します。

    これで私たちはオブジェクトを Meteor の Collection.update() メソッドに渡して、もしアップデートが失敗したら、( either?=どちらかの?)エラーを表示するコールバックを使います。  あるいは、アップデートに成功したらユーザーを投稿ページに送ります。

    Adding Links

    ユーザーが投稿の編集ページにアクセスする方法ができるように、私たちは投稿にリンクを加えます。

    <template name="postItem">
      <div class="post">
        <div class="post-content">
          <h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
          <p>
            submitted by {{author}}
            {{#if ownPost}}<a href="{{pathFor 'postEdit'}}">Edit</a>{{/if}}
          </p>
        </div>
        <a href="{{pathFor 'postPage'}}" class="discuss btn">Discuss</a>
      </div>
    </template>
    
    client/views/posts/post_item.html

    もちろん、私たちは (somebody else’s form?=誰かのフォーム)に編集リンクを 表示したくありません。  これは ownPostヘルパーが中に入る場所です。

    Template.postItem.helpers({
      ownPost: function() {
        return this.userId == Meteor.userId();
      },
      domain: function() {
        var a = document.createElement('a');
        a.href = this.url;
        return a.hostname;
      }
    });
    
    client/views/posts/post_item.js
    Post edit form.
    Post edit form.

    コミット 8-1

    Added edit posts form.

    投稿編集フォームは良さそうに見えますが、今は何も編集することはできません。 どういうことでしょうか。

    Setting Up Permissions

    私たちは以前にinsecureパッケージを削除したので、現在クライアントサイドでのすべての変更は拒否されます。

    これを修正するために、私たちはパーミッションルールを設定します。  最初に、lib内に新しく permissions.js ファイルを作ります。  これは最初にパーミッションロジックを読み込みます。(そして、両方の環境で使うことができます。)

    // check that the userId specified owns the documents
    ownsDocument = function(userId, doc) {
      return doc && doc.userId === userId;
    }
    
    lib/permissions.js

     投稿をつくるの章で、私たちは allow()メソッドを削除しました。というのも、私たちは allow()を回避するサーバーメソッドを使って新しい投稿を挿入していたためです。

    しかし、今はクライアントから投稿を編集して削除をするために、  posts.jsに戻って、allow() ブロックを加えましょう。

    Posts = new Meteor.Collection('posts');
    
    Posts.allow({
      update: ownsDocument,
      remove: ownsDocument
    });
    
    Meteor.methods({
      ...
    
    collections/posts.js

    コミット 8-2

    Added basic permission to check the post’s owner.

    Limiting Edits

    自分の投稿を編集できるからといって、あなたがすべてのプロパティを編集できるということではありません。  たとえば、私たちはユーザーが投稿を作って、だれかに投稿を割り当てるようにしたくありません。(???)

    ユーザーが特定のフィールドだけを編集できるようにするために、私たちは Meteor’s deny()コールバックを使います。 

    Posts = new Meteor.Collection('posts');
    
    Posts.allow({
      update: ownsDocument,
      remove: ownsDocument
    });
    
    Posts.deny({
      update: function(userId, post, fieldNames) {
        // may only edit the following two fields:
        return (_.without(fieldNames, 'url', 'title').length > 0);
      }
    });
    
    collections/posts.js

    コミット 8-3

    Only allow changing certain fields of posts.

    私たちは変更されたフィールドのリストを含んだ fieldNames配列を取得しています。  また、url や titleではないフィールドを含んだ(sub-array=下位の配列?)を返すために、Underscoreのwithout()メソッドを使います。

    すべてが標準の場合、この配列は空っぽで、長さは0になります。  だれかが何か(funky?=ファンキー?)なことをしたら、この配列の長さは1かそれ以上になって  コールバックは true を返します。(このようにアップデートを拒否します)

    Method Calls vs Client-side Data Manipulation

    投稿を作るために、私たちはpostメソッドを使います。一方で、投稿を編集したり削除したりするために、私たちは直接クライアントで update と remove を呼び出してallow とdenyでアクセスを制限しています。

    いつ( one?)を適切にして、(not the other?) でしょうか?(???)

    物事が 比較的単純で、あなたが適切に allow とdeny でルールを表現できます。

    クライアントから 直接データベースを操作することで、(perception of immediacy?)を作って、  あなたが優雅に失敗事例に対処することを忘れない限り、より良いユーザーエクスペリエンスに役立てることができます。   (つまり、結局はサーバーが変更を言い返す時は、うまくいきませんでした。)

    しかし、ユーザーのコントロールの範囲外にする必要になり始めるとすぐに  (たとえば、新しい投稿にタイムスタンプをしたり、正しいユーザーに(it?)を割り当てるなど)、  おそらく、メソッドを使うのが良いでしょう。

    メソッドコールはのいくつかのシナリオで適切です 。

    • 伝えるためのリアクティビリティと同期を待つよりも、コールバックから値を返すか知る必要の時(???)。
    •  多数のコレクションを(ship?)するにはコスト高になる( heavy ?)データベース機能のために。
    • データを要約して集約する場合(たとえば、count, average, sum)。