-
Notifications
You must be signed in to change notification settings - Fork 11
/
08-editing-posts.md.erb
289 lines (225 loc) · 10.7 KB
/
08-editing-posts.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
---
title: Editing Posts
slug: editing-posts
date: 0008/01/01
number: 8
contents: 投稿を編集するフォームを加えます。| 編集(permissions?=権限?)をセットアップする。|(Restrict which properties can be edited?)
paragraphs: 29
version: 1.7
---
これまでで投稿を作ることができたので、次のステップは投稿の編集と削除をできるようにすることです。
そうするための UI コードはとてもシンプルですが、
そろそろ Meteor でユーザーパーミッションを管理する方法を話す良い時期でしょう。
はじめに、ルーターをつなぎましょう。
私たちは投稿編集ページアクセスするためのルートを加えて、データコンテキストを設定します:
~~~js
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'});
~~~
<%= caption "lib/router.js" %>
<%= highlight "12~15" %>
### The Post Edit Template
これで私たちはテンプレートに集中することができます。
この postEdit テンプレートはスタンダードなフォームです:
~~~html
<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>
~~~
<%= caption "client/views/posts/post_edit.html" %>
そしてこれが(goes with it?)するpost_edit.jsマネージャーです。
~~~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');
}
}
});
~~~
<%= caption "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
ユーザーが投稿の編集ページにアクセスする方法ができるように、私たちは投稿にリンクを加えます。
~~~html
<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>
~~~
<%= caption "client/views/posts/post_item.html" %>
<%= highlight "5~8" %>
もちろん、私たちは (somebody else's form?=誰かのフォーム)に編集リンクを 表示したくありません。
これは ownPostヘルパーが中に入る場所です。
~~~js
Template.postItem.helpers({
ownPost: function() {
return this.userId == Meteor.userId();
},
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
~~~
<%= caption "client/views/posts/post_item.js" %>
<%= highlight "2~4" %>
<%= screenshot "8-1", "Post edit form." %>
<%= commit "8-1", "Added edit posts form." %>
投稿編集フォームは良さそうに見えますが、今は何も編集することはできません。 どういうことでしょうか。
### Setting Up Permissions
私たちは以前にinsecureパッケージを削除したので、現在クライアントサイドでのすべての変更は拒否されます。
これを修正するために、私たちはパーミッションルールを設定します。
最初に、lib内に新しく permissions.js ファイルを作ります。
これは最初にパーミッションロジックを読み込みます。(そして、両方の環境で使うことができます。)
~~~js
// check that the userId specified owns the documents
ownsDocument = function(userId, doc) {
return doc && doc.userId === userId;
}
~~~
<%= caption "lib/permissions.js" %>
投稿をつくるの章で、私たちは allow()メソッドを削除しました。というのも、私たちは allow()を回避するサーバーメソッドを使って新しい投稿を挿入していたためです。
しかし、今はクライアントから投稿を編集して削除をするために、
posts.jsに戻って、allow() ブロックを加えましょう。
~~~js
Posts = new Meteor.Collection('posts');
Posts.allow({
update: ownsDocument,
remove: ownsDocument
});
Meteor.methods({
...
~~~
<%= caption "collections/posts.js" %>
<%= highlight "3~6" %>
<%= commit "8-2", "Added basic permission to check the post's owner." %>
### Limiting Edits
自分の投稿を編集できるからといって、あなたがすべてのプロパティを編集できるということではありません。
たとえば、私たちはユーザーが投稿を作って、だれかに投稿を割り当てるようにしたくありません。(???)
ユーザーが特定のフィールドだけを編集できるようにするために、私たちは Meteor's deny()コールバックを使います。
~~~js
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);
}
});
~~~
<%= caption "collections/posts.js" %>
<%= highlight "8~13" %>
<%= commit "8-3", "Only allow changing certain fields of posts." %>
私たちは変更されたフィールドのリストを含んだ fieldNames配列を取得しています。
また、url や titleではないフィールドを含んだ(sub-array=下位の配列?)を返すために、Underscoreのwithout()メソッドを使います。
すべてが標準の場合、この配列は空っぽで、長さは0になります。
だれかが何か(funky?=ファンキー?)なことをしたら、この配列の長さは1かそれ以上になって
コールバックは true を返します。(このようにアップデートを拒否します)
<% note do %>
### 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)。
<% end %>