こんにちは!
キャスレーコンサルティングのSI(システム・インテグレーション)部の嵯峨です。
今回は、Sails.jsを利用して簡単なWEBアプリケーションを作ってみたいと思います。
Sails.jsとは
Sails.jsはMCVアーキテクチャーに基づくNode.js用フレームワークの一つで、名前の通り「Node.js用のRuby on Rails ライクなフレームワーク」です。
面倒くさい環境構築を省略し、スピーディに開発を開始できるらしい。との情報を、購入したNode.jsの書籍で目にし、
「いち早く画面作成に取り掛かりたい私にとって、とても嬉しいフレームワークになること間違いない!」と感じ、使ってみることにしました。
今回作成するアプリの概要
今回は、Sails.jsを利用し、「画面のリストの項目をドラッグ&ドロップで並び替えて、表示順をDBに反映する」WEBアプリを作成します。
ちなみに、このWEBアプリで並べ変えようと考えているのは、弊社の企業理念と行動規範である「CASM」です!
今回は公開されている3項目までしか表示出来ないのが残念ですが、こういうものを順番通りに覚えるのって大切ですよね。
CASMについては、弊社の社長ブログにて詳しく紹介されているので、興味のある方は是非ご覧になってください。
Node.jsのインストール
Sails.js を使う前提として、Node.js の動作環境が必要です。今回はWindows7にインストールをします。
Node.jsのサイトで最新のNode.jsをDOWNLOADSからWindows Installer(x86 or x64)をダウンロードし、インストールしてください。
今回は安定版のv4.4.7(2016年6月30日時点)をインストールしました。
npmの確認
Sails.js はnpmを使用して導入します。
npmとは、Node.jsのライブラリやパッケージを管理することができるツールですが、Sails.jsを導入するにはnpm のバージョンが 1.4.0 以上である必要があります。
まずは コマンドプロンプトにてnpm のバージョンを
npm --version
で確認します。
もし、バージョンが古い場合は以下コマンドでnpmをバージョンアップします。
npm update -g npm
Sails.jsのインストール
npm を使って Sails.js をインストールします。
※コマンドプロンプトは管理者権限で実行
npm install -g sails
2分~5分程時間がかかるので、少し待ちます。
プロジェクト作成
Sail.js のインストールが正常に完了したら、sails コマンドが使えます。
さっそく1つプロジェクト(casmapp)を作ってみましょう。
コマンドプロンプトでcdコマンドでアプリケーションを作成するディレクトリに移動し、以下のように入力します
sails new casmapp
フォルダ構成
生成されたフォルダ構成を見ると、MVCに対応するそれぞれのフォルダが配置されているのが分かります。
分かりやすいですね!
Controllerの作成
さっそく画面を作ろう!といきたいところですが、 コントローラーがないと画面表示もできないので、コントローラーを作成します。
コントローラーは以下のコマンドで作成できます。
sails generate controller 名前 アクション1 アクション2
ひとまず、casmコントローラーをindexアクションがついた状態で作成します。
sails generate controller Casm index
これでもう「sails lift」でサーバー起動していれば、作成したページにアクセスできる状態になります。
sails lift
ページは以下のurlでアクセス可能です。
http://ホスト名/コントローラー名/アクション名
今回は、
http://localhost:1337/Casm/index
にてアクセスできます。
まだ実装してない!」と表示されるので、実装を続けます。
/api/controllersに「CasmController.js」というファイルが出来ているのでindexプロパティを以下のように編集してください。
module.exports = { /** * `CasmController.index()` */ index: function (req, res) { return res.view({ title: 'CASM並び替え', no1 : '1', no2 : '2', no3 : '3', casm1 : 'CSVで発想する!', casm2 : '仕事に誇りをもつ!', casm3 : '良いものは良いと言える!' }); } };
res.view()メソッドを呼び出すことで、「view」フォルダ内のコントローラー名フォルダを探し、その中にあるアクション名のViewテンプレートをロードしてレンダリングします。
view()部分にオブジェクトのプロパティ名として指定されたtitle等が、Viewテンプレートの変数として利用できるようになります。
Viewの作成
コントローラー側で用意した値をHTMLに受け渡して動的に表示するため、Viewテンプレートのejsを使用します。
コマンドプロンプトを開き以下コマンドでejsをインストールしましょう。
npm install ejs
インストールが完了したら、「view」フォルダにコントローラーと同じ名前のフォルダを作り、そこにアクション名のejsを作成します。
■views/casm/index.ejsの中身
<h1><%=title %> <h1> <ul class="sortable"> <li id="<%=no1%>"><%=no1%><%=casm1%></li> <li id="<%=no2%>"><%=no2%><%=casm2%></li> <li id="<%=no3%>"><%=no3%><%=casm3%></li> </ul>
<%= %>で書かれたタグに変数名を指定するだけで、コントローラー側で用意した値を書き出すことが出来ます。
サーバーをリスタートさせて/Casm/indexにアクセスします。
sails lift
今度はこのリストのデータをDBから取得出来るように準備をします。
MySQLの準備
MySQLに接続する前に以下コマンドでモジュールをインストールします。
npm install -s sails-mysql
MySQLをインストールしたら、コマンドプロンプトを管理者として実行し、rootユーザーでMySQLサーバーへ接続します。
mysql -u root -p
それでは、さっそくデータの準備を行いましょう。
1)データベースを作成
CREATE DATABASE文を使って、「casley」という名前のデータベースを作成します。
CREATE DATABASE casley;
2)テーブルの作成
CREATE TABLE文にて「casley」データベースに「casm」テーブルを作成します。
このテーブルには数値型の「id」カラムと、文字列型の「casm」カラムが含まれます。
CREATE TABLE casley.casm (id int PRIMARY KEY, casm VARCHAR(300));
3)ユーザ登録(権限とパスワードの設定)
GRANT CREATE,SELECT,INSERT,UPDATE,DELETE,DROP ON casley.* TO user@localhost IDENTIFIED BY 'password'; FLUSH PRIVILEGES;
4)データの追加
デーブルが作成されましたので、sql文でデータを挿入します。
INSERT INTO casley.casm (id, casm) VALUES (1, "仕事に誇りをもつ!"); INSERT INTO casley.casm (id, casm) VALUES (2, "良いものは良いと言える!"); INSERT INTO casley.casm (id, casm) VALUES (3, "CSVで発想する!");
今回は順番通りにcasmを並び変える画面を作成するのが目的なので、casmの順番は適当に入力します!!
5)データ確認
SELECT文でデータの中身を確認して、準備完了です。
mysql> select * from casley.casm; +------+--------------------------+ | id | casm | +------+--------------------------+ | 1 | 仕事に誇りをもつ! | | 2 | 良いものは良いと言える! | | 3 | CSVで発想する! | +------+--------------------------+ 3 rows in set (0.00 sec)
データベース接続設定
まず、デフォルトDBの設定を config/models.js に記述します。
module.exports.models = { connection:"someMysqlServer", migrate: 'safe', autoCreatedAt: false, autoUpdatedAt: false };
続けてDB接続の定義をconfig/connection.jsに記述します。
someMysqlServer: { adapter : 'sails-mysql', host : 'localhost', user : 'user', password: 'password', database: 'casley' },
Modelの作成
Modelは以下コマンドで生成出来ます。
sails generate model Casm
「api/models/」フォルダにCasm.jsというファイルができているので、以下のように編集します。
module.exports = { attributes: { casm:'string' } };
attributesには、「カラム名:型名」という形で値を用意します。
Viewの修正
Viewテンプレートを修正します。
■views/casm/index.ejs
↓ 修正前
<h1><%=title %> <h1> <ul class="sortable"> <li id="<%=no1%>"><%=no1%><%=casm1%></li> <li id="<%=no2%>"><%=no2%><%=casm2%></li> <li id="<%=no3%>"><%=no3%><%=casm3%></li> </ul>
↓ 以下のように修正します。
<h1><%=title %> <h1> <ul class="sortable"> <% for(var i = 0; i < datas.length; i++){ %> <li id="<%=datas[i].id%>"><%=datas[i].id%><%=datas[i].casm%></li> <% } %> </ul>
for文で変数datasのデータを順に表示するよう変更しました。
Controllerの修正(アクション処理)
続いて、DBから値を取得するよう、アクションの処理を修正します。
↓ 修正前
module.exports = { /** * `CasmController.index()` */ index: function (req, res) { return res.view({ title: 'CASM並び替え', no1 : '1', no2 : '2', no3 : '3', casm1 : 'CSVで発想する!', casm2 : '仕事に誇りをもつ!', casm3 : '良いものは良いと言える!' }); } };
↓ 以下のように修正します。
module.exports = { /** * `CasmController.index()` */ index: function (req, res) { Casm.find().exec(function (err, records) { return res.view({ title: 'CASM並び替え', datas: records }); }); } };
title以外のデータを全てDBから取得するように変更しています。
データの操作はModelオブジェクトのメソッドを利用して行います。
Casmテーブルのデータを全検索する場合はCasmオブジェクトのfindメソッドを引数無しで呼び出します。
データの取得はfindの後にexecを実行することで、第一引数にエラー情報、第二引数に取得したデータが渡されます。第二引数はModelオブジェクトの配列になります。
「sails lift」コマンドでサーバーをリスタートさせて/Casm/indexにアクセスします
sails lift
DBの順番通りにデータが出力されるようになりました!
Sails.jsでJavascriptとCSSを読み込む
準備が整ったので、リストの項目をドラッグ&ドロップで並び替えられるようにしましょう!
まずページごとに外部のJavascriptとCSSを、ページに読み込めるようにするため、views/layout.ejsに以下の記述を追加します。
今回は、\assets\styles\casm.cssと、\assets\js\casm.jsを作成し、viewに取り込みます。
■views/layout.ejs
・・・・・ <!--STYLES--> <link rel="stylesheet" href="/styles/casm.css"><!--★「casm.css」を追加--> <link rel="stylesheet" href="/styles/importer.css"> <!--STYLES END--> ・・・・・ <!--SCRIPTS--> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%2Fjs%2Fdependencies%2Fsails.io.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22%2Fjs%2Fcasm.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /><!--★「casm.js」を追加--> <!--SCRIPTS END-->
1)jqueryとjquery-uiの読み込み↓
■views/casm/index.ejs
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22http%3A%2F%2Fcode.jquery.com%2Fjquery-1.8.3.min.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22http%3A%2F%2Fcode.jquery.com%2Fui%2F1.11.3%2Fjquery-ui.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" />
2)外部JavascriptとCSSを読み込み↓
■views/casm/index.ejs
<% script('/js/casm.js') -%> <% stylesheet('/styles/casm.css') -%>
3)ドラッグ&ドロップ可能リストをformで囲む↓
■views/casm/index.ejs
<h1><%=title %> <h1> <form action="/casm/sort" method="post"> <ul class="sortable"> <% for(var i = 0; i < datas.length; i++){ %> <li id="<%=datas[i].id%>" name="<%=datas[i].id%>"><%=datas[i].id%><%=datas[i].casm%></li> <% } %> </ul> <input type="hidden" id="result" name="result" /> </form>
action=”/casm/sort” 、method=”post”にフォーム送信すると、リストのIDが、上から順番にコンマ区切りの文字列として格納されるように記述します。
例えば、3,2,1 と並び替えれば、「3,2,1」が結果として返ります。
■views/casm/index.ejs(完成版)
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22http%3A%2F%2Fcode.jquery.com%2Fjquery-1.8.3.min.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22http%3A%2F%2Fcode.jquery.com%2Fui%2F1.11.3%2Fjquery-ui.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <% script('/js/casm.js') -%> <% stylesheet('/styles/casm.css') -%> <h1><%=title %> <h1> <form action="/casm/sort" method="post"> <ul class="sortable"> <% for(var i = 0; i < datas.length; i++){ %> <li id="<%=datas[i].id%>" name="<%=datas[i].id%>"><%=datas[i].id%><%=datas[i].casm%></li> <% } %> </ul> <input type="hidden" id="result" name="result" /> </form>
外部Javascriptの作成
■\assets\js\casm.js
$(function() { $(".sortable").sortable(); $(".sortable").disableSelection(); $(".sortable").sortable({ update: function(ev, ui) { var result = $(".sortable").sortable("toArray"); $("#result").val(result); $("form").submit(); } }); });
このJavaScriptでリストの項目をドラッグ&ドロップできるようになります!
sortable の toArray メソッドを指定することで、要素の id を配列として取得できます。
今回は、並び替えが終了したタイミングでsubmitするため、DOM要素の位置が変更されたときに呼び出される”update”イベントを使用しています。
Controllerにsortアクションを追加する。
最後に、api\controllers\CasmController.jsにsortアクションを追加して、並び替えたリストをDBに書き込む処理を記載します。
■api\controllers\CasmController.js
sort: function (req, res) { //req.body.result内に、リストのIDが上から順番にコンマ区切りの文字列で格納されています。 var result = req.body.result; console.log('取得した配列:'+result); //配列に格納 var result_array = result.split(','); /* ここからDBに格納する処理 */ //1_casmデータを全て取得し、引数recordsに格納しておく。 Casm.find().exec(function (err, records){ //2_casmデータを全て削除する。 Casm.destroy({}).exec(function createCB(err){ //3_recordsを元に、casmデータを再作成する。 var insertNum = 0;//idに対して番号を1からふる for(var num = 0 ; num < result_array.length ;num++){ //3-1_ログ書き出し console.log(records[result_array[num]-1].id + ':' + records[result_array[num]-1].casm + '→' + records[num].id + ':' + records[result_array[num]-1].casm); //3-2_データ追加処理 Casm.create({ id :records[num].id, casm:records[result_array[num]-1].casm }).exec(function insertRow(err){ insertNum++; if(insertNum == result_array.length){ //4_casmへリダイレクト res.redirect('/casm'); } }); } }); }); },
■api\controllers\CasmController.js(完成版)
module.exports = { /** * `CasmController.index()` */ index: function (req, res) { Casm.find().exec(function (err, records) { return res.view({ title: 'CASM並び替え', datas: records }); }); }, sort: function (req, res) { //req.body.result内に、リストのIDが上から順番にコンマ区切りの文字列で格納されています。 var result = req.body.result; console.log('取得した配列:'+result); //配列に格納 var result_array = result.split(','); /* ここからDBに格納する処理 */ //1_casmデータを全て取得し、引数recordsに格納しておく。 Casm.find().exec(function (err, records){ //2_casmデータを全て削除する。 Casm.destroy({}).exec(function createCB(err){ //3_recordsを元に、casmデータを再作成する。 var insertNum = 0;//idに対して番号を1からふる for(var num = 0 ; num < result_array.length ;num++){ //3-1_ログ書き出し console.log(records[result_array[num]-1].id + ':' + records[result_array[num]-1].casm + '→' + records[num].id + ':' + records[result_array[num]-1].casm); //3-2_データ追加処理 Casm.create({ id :records[num].id, casm:records[result_array[num]-1].casm }).exec(function insertRow(err){ insertNum++; if(insertNum == result_array.length){ //4_casmへリダイレクト res.redirect('/casm'); } }); } }); }); }, _config:{} };
動かしてみる。
これですべての実装が完了したので、「sails lift」コマンドでサーバーをリスタートさせて/Casm/indexにアクセスします。
これは完全に順番が間違っているので、並び変えます!
ドラッグして、、、
並べ変え完了!これは正しい!
ログも正しく出力されているようです。
mysql> select * from casley.casm; +----+--------------------------+ | id | casm | +----+--------------------------+ | 1 | CSVで発想する! | | 2 | 仕事に誇りをもつ! | | 3 | 良いものは良いと言える! | +----+--------------------------+ 3 rows in set (0.00 sec)
DBも書き換わっていることを確認して終了です!
お疲れさまでした!!
Sails.jsを使用してみた感想
実際に使ってみたところ、情報通り、私のような初心者でも簡単に環境構築をすることができました。モック作成などに重宝しそうですねー。
今回はcssまで手が回りませんでしたが、画面作成好きな自分にとっては手っ取り早く画面作成に取り掛かれるというのは、とてもワクワクします。
一方で、バージョンアップの速度が速いのか、参考資料やネットの情報通りに実装していても動かない事が多く、大分苦労しました。
もうちょい情報が(日本語で)探しやすいと嬉しいですねー。