Edited at

Sinatra with Vue.js で API と通信するアプリケーションを作ろう


これはなに

Sinatra で echo サーバを、 Vue.js でフロントを構築しようというチュートリアルです。

この記事では Sinatra, Vue.js どちらも触れて、 hello world を表示するところまで行います。

「ウェブアプリケーションを作りたいけど何からやっていいかわからない」、「Vue.js やりたいけど、フロントエンド周りがよくわからない」という方向けの記事になります。

入門にしては内容が多めですが、どれも Web開発をするためには便利なツールなので一度自分の手で実行してみることを推奨します。

全てのコードはこちらのリポジトリにあります。

https://github.com/Asuforce/sinatra_with_vue


取り扱うソフトウェア

雑に役割を書いてますが、ここで理解できなくても大丈夫です。

チュートリアルを進めながら学んでいきましょう。わからない部分はまずはリンクしてある公式サイトを見ることがオススメです。

全て 18/3/18 時点の最新のバージョン、シンタックスになるように努力しました。(改善点大歓迎です。



  • Sinatra


    • Webアプリケーションフレームワーク

    • さくっとサーバーサイドが作れます




  • Bundler


    • gemマネージャー

    • gem を管理できます




  • Slim


    • テンプレート言語

    • 楽に html が書けるオススメの gem です




  • RSpec


    • サーバーサイドのテストツール

    • Webアプリケーションの振る舞いをテストします




  • npm


    • jsパッケージマネージャー

    • js のライブラリを管理できます




  • Webpack


    • jsバンドラー

    • js ファイルを任意の設定でまとめてくれます




  • Vue.js


    • jsプログレッシブフレームワーク

    • UI を構築するためのフロントエンドライブラリです




事前準備

以下のソフトウェアを取り扱うので予めインストールしておいてください。バージョンは 18/3/18 のものになります。

あと簡単な Linux コマンドを多用するので、お好きなターミナルを起動しておいてください。


Sinatra でサーバサイドを作る


init

git 管理したい人は、ここで git init しておくと捗ります。

mkdir myapp

cd myapp
bundle init
echo gem \"sinatra\" >> Gemfile
bundle install -j4 --path vendor/bundle
touch app.rb


hello, world


app.rb

require "sinatra/base"

class MyApp < Sinatra::Base
get "/" do
'hello, world!'
end

run! if app_file == $0 # ファイルを読み込むとサーバを実行する
end


bundle exec ruby app.rb

http://localhost:4567 にアクセスして Hello world! が見えたら正常です。

Mac の場合以下のコマンドが便利です

open http://localhost:4567

git で管理している人は.bundle, venodr.gitignore に追加しましょう。

echo '/.bundle/\n/vendor/' > .gitignore


開発効率を向上させる

ここまでのアプリケーションでローカルサーバを立ち上げてから、 hello, world を変えて再アクセスしてみましょう。レスポンスが hello, world が変更されない筈です。現状はサーバの設定がリロードを実行しないと読み込まれません。

これでは効率が悪いので以下の設定で改善します。

sinatra-contribGemfile に追加します。

sinatra-contrib には他にも便利なライブラリがあるので下記を参考にしてみると発見があると思います。

Sinara-Contribまとめ

echo gem \'sinatra-contrib\' >> Gemfile

bundle install

app.rb に以下を書き加えます。


app.rb

 require "sinatra"

+require 'sinatra/reloader'

class MyApp < Sinatra::Application
+ configure :development do
+ register Sinatra::Reloader
+ end
+
get "/" do

これでローカルサーバを起動しながら、ガンガン変更ができるようになります。


Test を書く

簡単なアプリケーションができたので、テストも作成してみましょう。

ref: http://recipes.sinatrarb.com/p/testing/rspec

RSpec を使います。下記を Gemfile に追加します


Gemfile

 gem "sinatra"

gem 'sinatra-contrib'
+
+group :test do
+ gem 'rspec'
+ gem 'rack-test'
+end

bundle install して rspec --init を実行します。

bundle install

bundle exec rspec --init

spec/spec_helper.rb を下記のように書きましょう。


spec/spec_helper.rb

require 'rack/test'

require 'rspec'

ENV['RACK_ENV'] = 'test'

require File.expand_path '../../app.rb', __FILE__

module RSpecMixin
include Rack::Test::Methods
def app
MyApp
end
end

RSpec.configure { |c| c.include RSpecMixin }


spec/app_spec.rb を作成しテストを記述します。テストの内容はページのレスポンスと body の内容を確認するものです。

touch spec/app_spec.rb


spec/app_spec.rb

describe "My Sinatra Application" do

before :all do
get '/'
end

it "should allow accessing the home page" do
expect(last_response).to be_ok
end

it "should discribe message" do
expect(last_response.body).to eq('hello, world!')
end
end


テストが書けたら以下を実行して、実際に RSpec を実行してみましょう。

緑色の文字で 2 example, 0 failures と出たら成功です。

bundle exec rspec


View を表示する

Slim というテンプレートエンジンを使います。Ruby には標準ライブラリの ERB を用いる事が多いですが、今回はよりシンプルに記述できる Slim を使って View を作成します。

Slim の記法は以下の記事が大変参考になります。

マークアッパー的 Slim 入門21の手引き

echo gem \"slim\" >> Gemfile

bundle install
mkdir
views
touch views/index.slim


views/index.slim

doctype html

html
head
meta charset="UTF-8"
title MyApp
body
div id="app"
h1 hello, world

同じファイルを html で出力してみましょう。

bundle exec slimrb -p views/index.slim | cat

このような出力結果が得られます。Slim の方がスッキリした印象があると思います。


index.html

<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8" />
<title>MyApp</title>
</head>
<body>
<div id="app">
<h1>
hello, world
</h1>
</div>
</body>
</html>

アプリケーションのコードを変更して View ファイルを表示してみましょう。


app.rb

 require "sinatra/reloader"

+require "slim"

class MyApp < Sinatra::Base
configure :development do
register Sinatra::Reloader
end

get "/" do
- 'hello, world!'
+ slim :index
end


H1 タグで大きく表示されるようになっていたら成功です。


データの受け渡し

ここまでで静的なページを作ることができました。

次はアプリケーションからのパラメータを表示する例です。


app.rb

 get "/" do

+ @message = 'This is MyApp'
slim :index
end


views/index.slim

 body

div id="app"
- h1 hello, world
+ h1 = @message

ブラウザをリロードして This is MyApp と表示されたら成功です。

このままだとテストが失敗してしまうので、メッセージの内容を正しく書き直してテストをパスするようにします。


spec/app_spec.rb

   it "should discribe message" do

- expect(last_response.body).to eq('hello, world!')
+ expect(last_response.body).to include('This is MyApp')
end

再度テストを実行してパスすることを確認してください。


フロントエンドの作成


Vue.js の導入

予め のインストールをお願いします。

Node.js がインストールできたら以下を実行してください。package.json が作成されます。

# package.json を初期化します

npm init -y

# i = install
# -D = devDependencies に追加
npm i -D webpack webpack-cli

# Vue.js のインストール
npm i vue

./node_modules にモジュールがインストールされます。

このディレクトリは ignore します。

echo /node_modules/ >> .gitignore

今回は以下の設定が package.json にあれば十分です。(特にデフォルトから編集する必要はありません。が以下をベースに話を進めます。


package.json

{

"dependencies": {
"npm": "^5.7.1",
"vue": "^2.5.16"
},
"devDependencies": {
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}


webpack の準備

ref: 最新版で学ぶwebpack 4入門 – JS開発のモジュールバンドラ

Vue.js の導入を行なった際に webpack も導入しました。

これは高度な Web アプリケーションの構築のためのモジュールバンドラーです。js, css の minify をビルド時に実行することも可能です。

参考記事がとてもわかりやすいので、併せてご覧ください。

早速、webpack の設定を行いましょう。

touch webpack.config.js

以下の設定で ok です。

entry はデフォルトの src/index.js を使うので書きません。output は Sinatra が js ファイルを読み込む public 以下に作ります。


webpack.config.js

const path = require('path')

module.exports = {
output: {
path: path.join(__dirname, 'public', 'js'),
filename: 'main.js'
},
resolve: {
alias: {
'vue': 'vue/dist/vue.common.js'
}
}
};


ファイルとディレクトリなども作成しておきましょう。

mkdir src

touch src/index.js

mkdir public
touch public/.gitignore


Vue.js を記述する

早速、 Vue.js を使ってデータを表示していきましょう。

index.slim を以下のように設定します。

v-text はテキストコンテンツを表示するためのディレクティブです。よく {{message}} このような mustache 記法が使われる事が多いですが、DOM が構成された後に画面に描画されてしまうのを防ぐために v-text を使っています。

この問題は DOM が描画される前に js ファイルが読み込まれると発生します。footer で読み込んでいるのは header だと先述の問題が発生しやすいためです。知見がある方はこの現象の回避方法をご教授いただければと思います。


views/index.slim

   body

div id="app"
- h1 = @message
+ h1 v-text="message"
+ footer
+ script type="text/javascript" src="/js/main.js" charset="utf-8"

js ファイルはこのように記述します


src/index.js

Vue = require('vue')

new Vue({
el: '#app',
data: {
message: 'Hello world from Vue.js'
},
});


ここまでできたら build をしましょう。npm script を活用します。

--mode は Webpack4 からの機能になり、development, production が選べます。


package.json

     "webpack-cli": "^2.0.11"

},
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "build": "webpack --mode development"
}

以下のコマンドを実行して、ビルドを行います。

npm run build

build が終わったら public/js/main.js を確認してみましょう。Vue.js 本体を含む諸々が1個のファイルになってるのがわかります。

確認できたらローカルサーバを立ち上げて確認しましょう。画面に Hello world from Vue.js と表示されたら成功です。

この変更によって再度テストが落ちるようになっています。画面の描画は Vue.js が担うようになったので RSpec のテストの範疇を超えました。実際はフロントエンドテストフレームワークを使ってテストをするのが望ましいですが、今回は割愛させていただきます。

対象の部分を削除して、テストを通します。


spec/app_spec.rb

   it "should allow accessing the home page" do

expect(last_response).to be_ok
end
-
- it "should discribe message" do
- expect(last_response.body).to include('This is MyApp')
- end
end


まとめ

ここまでの作業で、Webアプリケーションの仕組みに触れながら、最新の環境を作成できるようになりました。

ここで作ったアプリケーションを使って自分なりの工夫をしてみるとより理解が深まると思います。