1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Meteor + Blaze で匿名質問サービスをつくろう:第5夜 DBコレクションと Pub/Sub

Last updated at Posted at 2018-02-26

Meteor + Blaze で匿名質問サービスをつくろう:第4夜 UI作成 前編 から続きです。

Meteor と MongoDB

Meteor の空恐ろしいところは、サーバー側の DB の一部をコピーして
クライアントにも持っているということです。

初期状態では、クライアントで DB に加えた編集がサーバー側にも適用される
ようになっていますので、例えば他人に寄せられた質問を読んだり、
編集・削除したりできてしまうんですよね。

これではセキュリティ的に非常にまずいので、なんとかします。

パッケージを削除

なんでプレインストールされているんだろう、とぼやきながら
DB の同期を行っているパッケージを削除します。
(For prototyping only) がついているふたつですね。

$ meteor list

accounts-twitter       1.4.1  Login service for Twitter accounts
accounts-ui            1.3.0  Simple templates to add login widgets to an app
autopublish            1.0.7  (For prototyping only) Publish the entire database to all clients
blaze-html-templates   1.1.2  Compile HTML templates into reactive UI with Meteor Blaze
ecmascript             0.10.0* Compiler plugin that supports ES2015+ in all .js files
es5-shim               4.7.3  Shims and polyfills to improve ECMAScript 5 support
insecure               1.0.7  (For prototyping only) Allow all database writes from the client
iron:router            1.1.2  Routing specifically designed for Meteor
meteor-base            1.3.0  Packages that every Meteor app needs
mobile-experience      1.0.5  Packages for a great mobile user experience
mongo                  1.4.2* Adaptor for using MongoDB and Minimongo over DDP
reactive-var           1.0.11  Reactive variable
shell-server           0.3.1  Server-side component of the `meteor shell` command.
standard-minifier-css  1.4.0* Standard css minifier used with Meteor apps by default.
standard-minifier-js   2.3.1* Standard javascript minifiers used with Meteor apps by default.
tap:i18n               1.8.2  A comprehensive internationalization solution for Meteor
tracker                1.1.3  Dependency tracker to allow reactive callbacks
twitter-config-ui      1.0.0  Blaze configuration templates for Twitter OAuth.


* New versions of these packages are available! Run 'meteor update' to try to update those packages to their
  latest versions. If your packages cannot be updated further, try typing `meteor add <package>@<newVersion>`
  to see more information.


$ meteor remove insecure autopublish

Changes to your project's package version selections:

autopublish  removed from your project
insecure     removed from your project

insecure: removed dependency
autopublish: removed dependency

これで、DBの同期は止まりました。
ついでに、更新のきているパッケージのアップデートもしておきます。

$ meteor update
This project is already at Meteor 1.6.1, the latest release.

Changes to your project's package version selections from updating package versions:

babel-compiler             upgraded from 7.0.0 to 7.0.5
base64                     upgraded from 1.0.10 to 1.0.11
ecmascript                 upgraded from 0.10.0 to 0.10.5
ecmascript-runtime-client  upgraded from 0.6.0 to 0.6.2
jquery                     upgraded from 1.11.10 to 1.11.11
meteor                     upgraded from 1.8.2 to 1.8.3
minifier-css               upgraded from 1.3.0 to 1.3.1
minifier-js                upgraded from 2.3.1 to 2.3.3
modules                    upgraded from 0.11.3 to 0.11.5
mongo                      upgraded from 1.4.2 to 1.4.4
promise                    upgraded from 0.10.1 to 0.10.2
rate-limit                 upgraded from 1.0.8 to 1.0.9
standard-minifier-css      upgraded from 1.4.0 to 1.4.1
standard-minifier-js       upgraded from 2.3.1 to 2.3.2

コレクションの準備

MongoDB コレクションを指定します。RDB ではテーブルに相当します。
サーバー・クライアントの双方からアクセスできるように、
shared ディレクトリに新しくファイルを作成します。

shared/Database.js
Questions = new Mongo.Collection('questions');

Development 環境では DB の設定は Meteor がやってくれますので、
特に何もする必要はありません。

また、accounts-ui パッケージを導入していれば、users コレクションが自動的に
作成されていますので、明示的な宣言は不要です。

この記事ではMongoDB 自体については詳しく扱いません。
詳しく知りたい方は適宜検索してください。

スキーマの定義 (Optional)

MongoDB にスキーマという概念はありませんが、この時点で DB に格納する
データのスキーマを決めておくことは悪くないはずです。

パッケージの追加

$ meteor add aldeed:simple-schema

aldeed:simple-schema: A simple schema validation object with reactivity. Used by collection2 and autoform.

autoform パッケージを入れるとついてくるのですが、今回は
autoform を使わないので手動でインストールします。

定義

さきほどの Database.js に追記します。

shared/Database.jsに追記
Questions.schema = new SimpleSchema({
    userId: { type: String, regEx: SimpleSchema.RegEx.Id },
    content: { type: String },
    isPublic: { type: Boolean, defaultValue: false },
    isAnswered: { type: Boolean, defaultValue: false },
    isDeclined: { type: Boolean, defaultValue: false },
    isReported: { type: Boolean, defaultValue: false },
    createdAt: { type: Date }
});

このスキーマを適用すると、データベースに格納されるデータはこんなイメージになるでしょう。

sample_data
{
    _id: "0e1b8263277ee31c8b3f2691",    // 質問ID。ユニーク。
    content: "進捗どうですか?",         // 質問の内容。
    userId: "7f34348aa6fcfd21f499f27e", // 質問相手の user._id。
    isPublic: false,                    // true なら大喜利モード。誰でも回答できる
    isAnswered: false,                  // true なら回答済。
    isDeclined: false,                  // 回答をスキップすると true にする。
    isReported: false,                  // 運営に通報すると true にする。
    createdAt: new Date()               // 投稿日時。
}

ユーザーがコンテンツを送信できるサービスは、必ず事務局に通報するボタンがあるのが最近の流行りです。
このことをすっかり忘れていました。入れておきます。

Publish / Subscribe の設定

さきほど autopublish insecure を削除したので、
DB とクライアントの同期については明示しないといけません。

Meteor では、 publish / subscription という仕組みで同期を実現します。

  • サーバー側

サーバーでは、DB のコレクションに名前をつけて publish します。
この名前はコレクション自体の名前とは無関係です。
中身は DB コレクションを返す関数なので、引数を受け取って特定のフィルターをかけることもできます。

  • クライアント側

クライアントでは、先程の名前を使って subscribe します。
サーバー上で関数を実行して返り値をもらうようなイメージですが、
subscribe では DB が変更されたときに、クライアントから関数を呼ばなくても自動的にデータがプッシュされてきます。
Reactive programming というやつですね。

この機能が不要で、ただ単に関数を実行したいときは methods / call という別の仕組みを使いますが、この説明はのちほど。

それでは、サーバーが questions コレクションを publish する宣言をします。

server/main.jsに追記
Meteor.publish('Questions', (type, query, limit) => {
    if (!limit) limit = 30;
    switch (type) {
        case 'public':
            return Questions.find({ isPublic: true }, { limit: limit });
        case 'specific':
            return Questions.find({ _id: query }, { limit: limit });
        case 'users':
            return Questions.find({ userId: query }, { limit: limit });
    }
});

必要な情報だけ絞って publish することで、表示速度とセキュリティの向上をはかります。
面倒でもコレクション全体を publish しないようにしましょう。

次にクライアントが subscribe する宣言を。

shared/Routing.js
Router.route('/', function() {
+   this.subscribe('Questions', 'public');
    this.render('Home');
});
Router.route('/user/:userid', function() {
+   this.subscribe('Questions', 'users', this.params.userid);
    this.render('User');
});
Router.route('/user/:userid/q', function() {
    this.render('Enqueue');
});
Router.route('/q/:qid', function() {
+   this.subscribe('Questions', 'specific', this.params.qid);
    this.render('Question');
});

パスパラメーターは this.params.hoge で取得できます。

ごめんなさい

前回、

第5夜ではモックアップと DB を結びつけていきます。

こんなことを書いたんですが、疲れたのでこのへんで……

ソースをGitHubで見る

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?