さいごにはじめに以前、Qiitaに書いた記事ですが、いくつか現行バージョンではうまくいかないという指摘があったため、やり直してみました。各バージョンは、2018年3月24日時点の安定版で試しています。作るもの簡単なTODOアプリです。TODOの管理はRailsのAPIで実施します。前提条件、及び環境Ruby、Rails、Node.jsの環境をご用意ください。下記の記事などが分かりやすいです。インストールとアップデートまた、Webpack、およびVue.jsはyarnでインストールされるため、yarnもインストールしておいてください。yarnを使ってみた本記事を書くにあたり、下記の環境で実施しました。ついて複数のJSファイルをひとまとめにするモジュールバンドラーのことです。複数ファイルに分割して管理しつつ、サーバーへのリクエスト数を削減することができるようです。JavaScript開発で人気のバンドルツール準備まずはもろもろインストールをしていきます。こちらの記事が動画つきで非常に分かりやすいので、もし初めて実施される方はご覧になった方が良いかと思います。Vue.jsのプロジェクトを作成するはじめから--webpackオプションを使用してプロジェクトを作成します。sでRailsのウェルカムページが表示されれば大丈夫です。基本的に、Railsで用意するビューファイルは1つのみで、そこを差し替えていきます。以下のファイルを作成、編集します。%>javascript_pack_tagを使用することで、app/javascript/packs以下にあるJSファイルを探してくれます。インストール時にhello_vue.jsというファイルが生成されているので、これをindexにて読み込ませます。Vue!」と表示されれば大丈夫です。devサーバーを設定するVue.js(というよりWebpack)関連のファイルは変更したらコンパイルする必要があります。コンパイルには、bin/webpackというコマンドを使用する必要があります。毎回コンパイルするのは面倒なので、変更を検出して自動コンパイルするようにします。こちらの記事でも紹介されております。WebpackerまずはforemanのGemをインストールします。foremanはProcfileから複数のプロセスを管理することができます。installします。次に下記2点のファイルを作成します。./bin/webpack-dev-serverまた、bin/serverのパーミッションを変更しておきます。bin/serverこれでbin/serverを実行してみると、http://localhost:5000で起動します。(ポート番号が変わります。)ここで、app.vueの下記の部分を変えて保存すると、コンパイル処理が走り、画面がリロードされるはずです。適当に変えて遊んでみて、問題なさそうなら大丈夫です。Vue!"}}}APIの準備サーバーサイドのAPI部分を実装していきます。テーブルとモデルの生成テーブル名はtasksとし、下記のようにします。generateで作成してしまいます。falseを追記するため、下記のように編集します。falset.timestampsendendendマイグレーションを実行します。db:migrateついでに、モデルのnameプロパティにバリデーションをつけておきましょう。trueendコントローラーと返却するJSONファイルを生成アクセスするURLは/api/tasksのように名前空間を切りたいと思います。ルーティングからです。endend次にコントローラーを作成します。コントローラーはapp/controllersの中にapiというディレクトリを作成し、そこに作ります。:is_done)endendビューのJSONファイルも同様に、views/api/tasks以下に作成します。:updated_atendseeds.rbを作成し、curlコマンドで確認seeds.rbを作成し初期データを作成できるようにします。レコードが増えすぎてもこれでやり直しもできます。db:setupcurlコマンドを使用してAPIの確認をします。Task","is_done":true,"created_at":"2017-09-14T08:12:35.475Z","updated_at":"2017-09-14T08:12:35.475Z"}]}次にPOSTで新規作成してみます。ここで恐らくエラーになるかと思います。確認すると、ActionController::InvalidAuthenticityTokenというエラーのようです。CSRF対策のトークンがないため、Railsから怒られてしまいます。application_controller.rbの下記をコメントアウトするとエラーが出なくなります。本来であれば、API認証のようなものをつけた方が良いとは思いますが、今回は割愛します。:exceptionこれで作成されたTODOが返却されるかと思います。'task[name]=fugafuga'{"task":{"id":6,"name":"fugafuga","is_done":false,"created_at":"2017-09-14T08:31:17.100Z","updated_at":"2017-09-14T08:31:17.100Z"}}Materializeの導入CSSはMaterializeというフレームワークを使用しようと思います。マテリアルデザインを意識したものになっており、個人的に使ってみたいと思っておりました。Gemもすでにあるので、Rails側でインストールします。installした後、下記の2ファイルに追記します。cssはscssに変更しておきます。'material_icons';$primary-colorと$secondary-colorを設定しておくことで、よしなに色を合わせてくれます。カラースキームはこちらを参照してください。.コンポーネントを使ってヘッダーを作成ここからVue.jsを中心に画面を作っていきます。ヘッダーを作成します。元となるビューファイルはRailsのindex.html.erbになるので、こちらにVue.jsを載せられるようにします。%><navbar>というタグがありますが、Vue.js側でこのタグとコンポーネントを紐付け、表示します。コンポーネントまた、新しくtodo.jsというファイルをapp/javascript/packsに作成します。(hello_vueを修正したも良いのですが。'vue/dist/vue.esm.js'としています。これは、後ほどコンポーネントを使用する際に完全ビルドする必要があるからだそうです。(すいません、まだよく分かっていません。)詳しくはこちらの方が解説記事を書いてくださっています。id="app">にマウントされます。このまま実行しても特に何もありません。それではコンポーネントを作成します。packsの下にcomponentsディレクトリを作成して、そこにheader.vueを作成します。コンポーネントは.vueで作成します。right">arrow_drop_down</i></a></li></ul></div></nav></div></template>これをtodo.jsに登録します。}});navbarという名前でコンポーネントとして登録します。(headerだと<header>タグがすでにHTML5に存在しているため。)これで<navbar>タグが使用できるようになりました。サーバーを再起動してアクセスすると下図のようなヘッダーができているのではないでしょうか?Vue-Routerを使用してSPAっぽくVue-Routerを使用することで、登録されたパスとコンポーネントで画面内を差し替えることができます。Vue-Routeryarnを使ってvue-routerを追加します。vue-router今回は「TODO一覧(メイン画面)」、「アバウト(おまけ)」、「コンタクト(おまけ)」を用意します。メイン画面でTODO管理はできるので、あと2つはおまけです。コンポーネントを作成します。address.</p><p>test@example.com</p></div></template>さて、このコンポーネントとパスを登録するrouter.jsを作成します。こちらもrouterディレクトリを作成してそちらに作成します。},],})パスとコンポーネントを結びつけます。APIを使用して、一見同じビュー内ですがURLを書き換えることができます。Historyモードまた、VueRouterを使用すると、<router-link>と<router-view>というタグが使用できます。<router-link>は、<a>タグとして変換されますが、画面遷移ではなくVueRouterに登録されたパスからコンポーネントを探します。<router-view>の部分に表示します。ヘッダーの各リンクを修正します。to="/contact">Contact</router-link></li>それぞれのコンポーネントが表示される部分をindex.html.erbに作ります。%>最後に、todo.jsに追加します。Header,}});これで、ヘッダーの各リンクを押すと本文が切り替わるのではないでしょうか?URLもHistoryモードのおかげで書き換わっています。http://localhost:5000/aboutでリロードすると、Rails側でエラーになってしまいます。たしかにroutes.rbで登録していません。/aboutでも/contactでもHome#indexにとぶよう記述します。'home#index'これでhttp://localhost:5000/aboutにアクセスするとわかりますが、ちゃんとURLからAboutのコンポーネントを表示してくれます。Axiosを使ってAPI通信axiosは、Ajax通信ライブラリです。これをインストールします。axiosAxiosを使用してindex.vueにてAPI通信してタスク管理したいと思います。完成イメージをindex.vueのtemplate内に記載します。これを書き換えていきます。Task</label></li></ul></div></div></template>こんな感じになります。一覧表示コンポーネントの中でHTML、JS、CSSをまとめて記載することを単一コンポーネントというようです。.vueファイルの中で、そのコンポーネントで使うJSも記述することができます。一覧をAPIで取得するために必要なものを追記します。</script>インスタンスにプロパティとしてtasksとnewTaskを与えます。メソッドとしてfetchTasksを登録し、APIで取得してきた値をループさせてtasksに格納します。AxiosはJQueryと同じ感じで使えるので、使用しやすいかと思います。mountedはVueインスタンスがマウントされたタイミングで実行されるライフサイクルフックです。createdもあって今回の場合、あまり違いはありませんが、ライフサイクルダイアグラムについては、ちゃんと理解する必要がありそうです。template内の下記の部分を書き換えます。(未完了と完了済みを両方変えます。)v-forとv-ifを使ってtasksプロパティの中で条件に合うものを表示しています。条件付きレンダリングまた、v-bindで強引にid名を作っています。</li></ul></div>完了済みタスクを常に表示させておく必要はないと思います。display_noneというクラスをつけているので、ここに非表示のスタイルをあてたいと思います。単一コンポーネントではCSSも管理できます。デフォルトの設定だと、コンパイル時に別でスタイルシートを出力してしまうので、これを無しにします。falseと修正すれば良いようです。falseindex.vueにスタイルを追記します。<style>タグ中にscopedという属性をつけておくと、そのファイルのみで有効なスタイルとして認識してくれます。そのコンポーネントでしか使わないようなクラスはここで定義してしまえば良さそうです。}}がそのまま文字列としてレンダリングされてしまいます。(インスタンスに値がセットされたら、その値が表示されます。none;と組み合わせて使うと、インスタンスが生成されたタイミングで表示してくれます。</style>これで完了済みの方は非表示になったかと思います。ボタンを押すと、完了済みエリアが表示されるまずはVueのmethodsにボタンを押されたときのメソッドを登録します。},}}「ボタンを押されたとき」と記載するのはかなり簡潔にかけます。テンプレートの方でv-onを使用してクリックされたタイミングでdisplayFinishedTasksを呼んでもらいます。tasks</div>新規作成フォームをつくるv-modelを利用することで、双方向バインディングさせることができます。これで<input>タグで入力された値とインスタンスのnewTaskプロパティをバインドさせます。task!!">次に新規作成のメソッドを追加します。APIで新規作成できた場合は、tasksプロパティの先頭に追加するようにします。}}チェックをつけたら完了済みに移すまずはチェックボックスにチェックがついたら更新メソッドを呼ぶようにしたいと思います。(この辺りは毎回呼ばずに、一定時間で同期させても良いかもしれません。}}</label></li></ul></div>更新用のメソッドを追加します。更新したタイミングで、未完了部分から消し、完了済みの方に追加します。(このあたりの処理はもっと良い書き方がある気がします。}}ここまでで、下図のような動きができるかと思います。(いくつかスタイルはたしました。)テストコードを書いてみる試しにテストコードを書いてみました。RailsのSystemTestCaseで書いております。理由は、Node.jsのテストフレームワークは(私にとって)学習コストが高いためです。本当はフロントエンドと分けるのであれば、テストも分けた方が良いのではないかと思っています。https://github.com/naoki85/todo_app_with_vue_and_rails/commit/4a5225395fa2fe6ba9c7a3f8a421648ab28c897cテストの中で、withinを使用していますが、今回の場合は使用する必要はないと思います。今後、さらに詳細なテストをする際に使用するかもと思い、残したままにしてあります。記事にできるほど試していないため、参考程度にご覧ください。さいごに今回は、状態管理に便利なVuexは今回できなかったため、機会があればまた書きたいと思います。よろしければご意見いただけると嬉しいです。参考にさせていただいたドキュメント、記事などは下記になります。falseの設定ですが、こちらの記述をloader/vue.jsにするのが正しいです。補足していただきありがとうございます。PMとても参考になりました。ありがとうございます。記載が漏れているようです。コメントをキャンセルメールアドレスが公開されることはありません。コメント名前メールアドレスサイト上に表示された文字を入力してください。私たちは無料アプリもリリースしています、ぜひご覧ください。下記のアイコンから無料でダウンロードできます。