BtoBtoC(BtoBtoBでも可)向けのアプリの場合、そのアプリを提供している会社向けに管理画面を提供したいと考えることがあります。その管理画面では、利用企業が自分たちのデータについてだけメンテナンスできるようになります。
そのための管理画面を作成していきます。今回は前回のベースを踏まえて、マスター管理処理を作っていきます。
マスター管理は一社一行で
一般的なデータベースで考えた場合、リレーションを組むためにマスタは一行に一つのデータになるでしょう。しかしNoSQL型データベースの場合、リレーションを用いる訳ではないのでデータの重複を恐れない方が良いでしょう。
また、100行のマスターを各社がもった場合、100社だけで1万行になってしまいます。そうしたデータの増加を防ぐためにもデータを一行で管理する方が便利です。そこで使いたいのがデータストアの配列になります。
マスター管理はAjaxで
マスター管理をWeb上で行う場合に面倒なのが、行を追加したり減らす、更新などをサーバサイドでレンダリングしようとすることです。テーブルタグを生成するのは面倒ですし、何番目のデータを削除すると言った情報を送り合うのも大変です。
そこで今回はVueとAjaxを使って実装する方法を紹介します。
Vueの読み込み
VueはReactのようにバーチャルDOMによってUIを構築します。しかし表示に特化している分、軽量で扱えるライブラリです。インストールはBowerを使って行い、views/layout.jadeで読み込みます。
bower install vue --save
views/layout.jadeは以下のScriptタグを追加します。
script(src='/vendors/vue/dist/vue.min.js')
ログイン後のページからリンク追加
次に views/index.jade にマスターメンテナンス用の画面へのリンクを追加します。パスは /masters とします。
p a.btn.btn-info(href='/masters') マスターメンテナンス
マスターメンテナンス画面の作成
マスターデータを編集する画面はVueに沿って記述していきます。殆どJadeのままですが、v-on:clickというのが特徴になります。これはボタンを押した際などのイベントでVue内で指定したメソッドを呼ぶ記述になります。
また、v-modelという表記があります。これはデータバインディングを行うための指定で、リストになるマスターデータをバインディングしながら表示します。
extends ../layout block content div#app h1 マスター管理 p button.btn.btn-default(v-on:click='add_item') 追加 button.btn.btn-info(v-on:click='save') 保存 table.table tr(v-for='(item,index) in items') td div.row div.col-xs-8 input.form-control(type='text',v-model='items[index]') div.col-xs-4 button.btn.btn-warning.btn-xs(v-on:click='delete_item(index)') 削除
Webブラウザ向けJavaScriptの記述
では次にWebブラウザ側のJavaScriptを記述します。これは public/javascripts/app.js に記述します。Vueの細かい使い方については省きますが、AjaxでGET /masters/items の結果を取得してitemsに格納します。これで一覧表示が行えます。
行を追加する場合はitemsを追加するだけで、削除も同様にspliceメソッドを使って行います。最後にデータの保存処理は itemsをそのままサーバ側に送っています。
$(function() { var app = new Vue({ el: '#app', data: { items: [] }, created: function() { var me = this; $.ajax({ url: '/masters/items' }) .then(function(master) { me.items = master.items; }) }, methods: { add_item: function() { this.items.push(""); }, delete_item: function(index) { this.items.splice(index, 1); }, save: function() { var me = this; $.ajax({ url: '/masters/items', type: 'POST', data: { items: me.items } }) .then(function(items) { console.log(items); }) } } }) })
サーバ側の処理
ファイル名は routes/masters.js になります。サーバ側では最初にHTMLを表示する処理に加えて、データの一覧を返す処理と保存/更新処理を行う部分を実装します。基本形は設定画面の時と変わりません。
let express = require('express'); let router = express.Router(); let ncmb = require('../libs/ncmb'); let user = null; let Master = ncmb.DataStore('Master'); // 認証済みかチェック router.all('*', (req, res, next) => { user = req.session.user || null; if (!user) { return res.redirect('/'); }else{ ncmb.sessionToken = user.sessionToken; next(); } }); // 画面表示 router.get('/', (req, res, next) => { res.render('masters/index', {user: user}); }); // 現在のデータをJSONで返す router.get('/items', (req, res, next) => { }); // データを更新する router.post('/items', (req, res, next) => { }); module.exports = router;
現在のデータをJSONで返す
データを返す部分は次のようになります。データストアのMasterクラスを検索し、取得できたデータ(なければ配列部分を初期化)してJSONで返します。
// 現在のデータをJSONで返す router.get('/items', (req, res, next) => { Master .where({Company: user.Company}) .fetch() .then(master => { if (Object.keys(master).length === 0) { master = new Master master.set('items', []); } res.json(master); }) .catch(error => { res.status(401).render('error', {error: error}); }) });
データを更新する
データを更新する場合も設定画面と同様に現在のデータがなければ初期設定としてACLを設定します。後は配列データを配列のままセットしてNCMBで保存します。
// データを更新する router.post('/items', (req, res, next) => { Master .where({Company: user.Company}) .fetch() .then(master => { if (Object.keys(master).length === 0) { // 新規作成 master = new Master; // Acl設定 let acl = new ncmb.Acl; acl.setRoleWriteAccess(user.Company, true) .setRoleWriteAccess('Admin', true) .setPublicReadAccess(true); master.set('acl', acl); master.set('Company', user.Company); } master.set('items', req.body['items[]']) if (master.objectId) { return master.update(); }else{ return master.save(); } }) .catch(error => { res.status(401).render('error', {error: error}); }) .then(master => { res.json(master); }) });
配列データは管理画面で見ても分かる通り、配列のまま保存できます。どのデータを消すかなどは考えず、そのまま適用して保存できます。
masters.jsをapp.jsに登録
最後にルーティング情報をapp.jsに追加します。
var masters = require('./routes/masters'); app.use('/masters', masters);
ここまでの処理でビジネス用途でありがちなマスターデータ管理ができるようになります。配列を使うことでデータ管理がとてもシンプルになります。少し応用して配列ではなくオブジェクトを使えば値を別名で保存するような使い方もできたり、多言語対応もできるようになります。
今回までのコードはNCMBMania/BtoB_Management at v0.3にて確認できます。実装時の参考にしてください。