はじめに
最近Vue.jsの勉強をしているtonnyです。
前回は、DockerでRails + Vue.jsの環境を作ってみる記事を書かせていただきました。
今回はその環境を使用して、以前のTODOアプリにサーバーサイドAPIを追加したいと思います。
今までの記事はこちらになります。
- Vue.js入門その1〜基本文法〜
- Vue.js入門その2〜Vueインスタンスってなんぞ?〜
- Vue.js入門その3〜簡単にTODOアプリを作ってみたよ〜
- DockerでRails + Vue.jsの環境を作ってみる
準備
今回作成したいもの
動きとしては、以前のTODOアプリと同じです。
- タスク一覧画面
- タスク新規登録機能
- タスク完了機能(論理削除)
環境構築
今回は、DockerでRails + Vue.jsの環境を作ってみるをそのまま使おうと思いますので、環境構築の詳細は割愛します。
Rails環境がすでに整っている方は、下記のコマンドでVue.js込みの新規プロジェクトを作成できます。
1 | $ rails new my-project --webpack=vue |
また、Node.jsも使用しますので、合わせてインストールしておいてください。
サーバーサイド
Scaffoldを使用して省エネ実装したいと思います。
また、Vue.js部分のコードを記事で書きたい関係上、Rails部分のコードはGithubリンクのみで失礼します。
(記事が無駄に長くなってしまうので。。。)
DB
タスクは、タスク名と完了したかどうかのフラグだけあれば良いかと思いますので、下記のような簡単なテーブルを作成します。
No | カラム名 | 型 | NULL制約、デフォルト | メモ |
1 | id | INTEGER | NOT NULL、AUTO INCREMENT | |
2 | name | VARCHAR | NOT NULL | タスク名 |
3 | is_done | TINYINT | NOT NULL、DEFAULT 0 | 完了フラグ(0: 未完了、1: 完了) |
4 | created_at | DATETIME | NOT NULL | 作成日 |
5 | updated_at | DATETIME | NOT NULL | 更新日 |
メモ:rails generateで余分なファイルを生成しない
Scaffoldで生成していくと、CSSやJS、テストなども生成されます。
これはこれで便利なのですが、今回のように特に実装する予定がないときや、自分で作成したい場合などは、いささか鬱陶しいです。
config/application.rb
に追記することで、
rails generate
する場合の生成ファイルを制御できます。
今回は
assets
ファイルと
helper
、およびテストを生成しないようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | module RailsVuePractice class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.1 # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. + config.generators do |g| + g.assets false + g.helper false + g.test_framework false + end end end |
作成したファイル
APIなので、
routes.rb
では
namespace
を切ってルーティングを生成します。
例えば、タスク一覧を取得するAPIは、
/api/tasks
といった具合になるようにします。
Scaffoldで生成される、余分なアクションは消去しておきます。
また、JSONで返却したいので、ビューは
jbuilder
を使用しました。
試しに数件レコードを登録して、
curl
で確認してみてください。
1 2 | $ curl -XGET localhost:3000/api/tasks {"server_time":1502633984,"return_code":0,"tasks":[{"id":1,"name":"test1","is_done":false,"created_at":"2017-08-13T14:18:23.000Z","updated_at":"2017-08-13T14:18:23.000Z"},{"id":2,"name":"test2","is_done":false,"created_at":"2017-08-13T14:18:33.000Z","updated_at":"2017-08-13T14:18:33.000Z"}]} |
作成、編集したファイルはGithubをご覧ください。
https://github.com/naoki85/rails-vue-practice/tree/todo_application
ビューの作成
JQueryとBootstrapを取得
今回もBootstrapを使用したいので、Gemfileに記載して
bundle install
します。
Rails 5.1からはJQueryがデフォルトから外れてしまったので、JQueryもインストールしておきます。
1 2 | gem 'jquery-rails' gem 'bootstrap-sass', '3.3.6' |
1 2 3 4 5 6 7 8 9 | /* * 省略 *= require_tree . *= require_self */ /* Bootstrap */ @import "bootstrap-sprockets"; @import "bootstrap"; |
1 2 3 4 5 6 | // 省略 //= require jquery //= require bootstrap-sprockets //= require rails-ujs //= require turbolinks //= require_tree . |
もとになるビューを作成
まずは、TODOアプリを描画する部分のコントローラーとビューファイルを作成します。
1 2 3 4 | class TodoController < ApplicationController def index end end |
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 | <h1>All Tasks</h1> <table id="todo-index" class="table table-striped"> <thead> <tr> <th>Name</th> <th></th> </tr> </thead> <tbody> <tr v-for="task in tasks" v-if="!task.is_done"> <td>{{ task.name }}</td> <td> <div class="btn btn-danger" v-on:click="doneTask(task.id)">Done!</div> </td> </tr> <tr> <td><input v-model="newTask" class="form-control"></td> <td> <div class="btn btn-default" v-on:click="createTask">Create Task</div> </td> </tr> </tbody> </table> <%= javascript_pack_tag 'todo_vue' %> |
ビューファイルは、前回のVue.js入門その3〜簡単にTODOアプリを作ってみたよ〜を使いました。
なお、
javascript_pack_tag
と記載することで、後ほど作成するVue.jsのファイルを読み込むことができます。
Vue.jsのファイルの作成
webpack
でインストールすると、
app
ディレクトリの下に、
javascript
ディレクトリができているかと思います。
さらにそのディレクトリの下に、
packs
というディレクトリがあります。
その中に今回は
todo_vue.js
というファイルを作成します。
まずはVueインスタンスに
data
プロパティを持たせるところまで記載します。
1 2 3 4 5 6 7 8 9 10 | // Vue.js本体をインポートします。 import Vue from 'vue' var app = new Vue({ el: '#todo-index', data: { tasks: [], newTask: '' }, }); |
tasks
プラパティは、はじめは空配列にしておき、インスタンス生成時にAjaxでタスク一覧を取得したいと思います。
Ajax通信に便利なaxios
axiosは、Ajax通信ライブラリです。
まずはこれをインストールします。
1 | $ npm install axios |
さて、それではインスタンスが生成されたタイミングで、タスク一覧を取得したいと思います。
まずは
axios
をインポートすることで、使用可能になります。
Vue.jsにはcreatedフックがあるため、そちらに登録してあげます。
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 | import Vue from 'vue' import axios from 'axios'; var app = new Vue({ el: '#todo-index', data: { tasks: [], newTask: '' }, created: function() { app.fetchTasks(); }, methods: { fetchTasks: function() { axios.get('/api/tasks').then(function(response) { // success for(var i = 0; i < response.data.tasks.length; i++) { app.tasks.push(response.data.tasks[i]); } }, function() { // error alert('Sorry, server error occurred. Please reload.') }); } } }); |
後々、一覧表示は使用しそうなので、
methods
に登録しておきます。
axios
から
get
でつなぐことでGETリクエストできます。
このあたりはJQueryと似たような感覚で使用できます。
新規登録と完了も実装してしまう
基本的には流れは、
- 新規作成、もしくは更新のAPIを叩く
- レスポンスが返ってきたら、再度一覧のAPIを叩く
とします。
(再度一覧のAPIを叩くことは良くないので、改善の余地があります。)
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 | methods: { fetchTasks: function() { axios.get('/api/tasks').then(function(response) { // success for(var i = 0; i < response.data.tasks.length; i++) { app.tasks.push(response.data.tasks[i]); } }, function() { alert('Sorry, server error occurred. Please reload.') }); }, + createTask: function () { + axios.post('/api/tasks', { task: { name: app.newTask } }).then(function() { + app.refreshTasks(); + }, function() { + alert('Saving a Task is failed') + }); + }, + doneTask: function (task_id) { + axios.put('/api/tasks/' + task_id, { task: { is_done: 1 } }).then(function() { + app.refreshTasks(); + }, function() { + alert('Saving a Task is failed') + }); + }, + refreshTasks: function() { + app.tasks = []; + app.fetchTasks(); + } } }); |
再度一覧APIを叩いてリロードするのは、
refreshTasks()
という関数にしています。
ここまで実施していただければ、Vue.js入門その3〜簡単にTODOアプリを作ってみたよ〜と同じような動きをしつつ、DBに保存できるかと思います。
ソースコードはこちらになります。
https://github.com/naoki85/rails-vue-practice/tree/todo_application
さいごに
前回の記事を少し改良してみました。
まだ、コンポーネントは使用していないので、次回はコンポーネントに関して記載できればな、と思います。