RailsでAPIサーバーとVue.jsの描画

はじめに

想像以上に簡単だったので今後Reactなどでも試していきたい。

✅参考

Vue.jsとRailsでTODOアプリのチュートリアルみたいなものを作ってみた

Ruby on Rails, Vue.js で始めるモダン WEB アプリケーション入門

セットアップ

プロジェクト生成

$ rails new todo_sample --webpack=vue

コントローラ生成

$ rails g controller home index
create app/controllers/home_controller.rb
route get 'home/index'
invoke erb
create app/views/home
create app/views/home/index.html.erb
invoke test_unit
create test/controllers/home_controller_test.rb
invoke helper
create app/helpers/home_helper.rb
invoke test_unit
invoke assets
invoke coffee
create app/assets/javascripts/home.coffee
invoke scss
create app/assets/stylesheets/home.scss

routes.rb

Rails.application.routes.draw do
  root to: 'home#index'
  get 'home/index'
end

home/index.html.erb

<%= javascript_pack_tag 'hello_vue' %>

javascript_pack_tagを使用することで、app/javascript/packs以下にあるJSファイルを探してくれます。インストール時にhello_vue.jsというファイルが生成されているので、これをindexにて読み込ませます。
これでrails sして、「Hello Vue!」と表示されれば大丈夫です。

確認したところ表示されました◎

👇ファイルの確認

※いったん失敗したので割愛 起動できない。。。

参考:foreman で アプリケーションを動かす。

gemの追加でリロードすることで自動コンパイルがされるようにします。

gem 'foreman'

インストール

$ bin/bundle

※bundleコマンドなかった💦

bin/server作成

#!/bin/bash -i
bundle install
bundle exec foreman start -f Procfile.dev

Procfile.dev

web: bundle exec rails s
# watcher: ./bin/webpack-watcher
webpacker: ./bin/webpack-dev-server

bin/serverのパーミッション変更

$ chmod 777 bin/server

app/javascript/app.vueの編集

<template>
  <div id="app">
    <p>Rails × Vue.js</p>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue.js!"
    }
  }
}

</script>
<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>

再度サーバー起動で自動コンパイル確認

$rails s

APIサーバー構築

モデル作成

$ rails generate model Task name:string is_done:boolean
invoke active_record
create db/migrate/20200721122943_create_tasks.rb
create app/models/task.rb
invoke test_unit
create test/models/task_test.rb
create test/fixtures/tasks.yml

マイグレファイル編集(null: false追記)

create_table :tasks do |t|
  t.string :name, null: false
  t.boolean :is_done, default: false, null: false
  t.timestamps

実行

$ rails db:migrate

モデル編集

class Task < ApplicationRecord
  validates :name, presence: true
end

routes.rbの編集

Rails.application.routes.draw do
  root to: 'home#index'
  namespace :api, format: 'json' do
    resources :tasks, only: [:index, :create, :update]
  end
end

コントローラ作成

$ rails g controller api/tasks index
create app/controllers/api/tasks_controller.rb
route namespace :api do
get 'tasks/index'
end
invoke erb
create app/views/api/tasks
create app/views/api/tasks/index.html.erb
invoke test_unit
create test/controllers/api/tasks_controller_test.rb
invoke helper
create app/helpers/api/tasks_helper.rb
invoke test_unit
invoke assets
invoke coffee
create app/assets/javascripts/api/tasks.coffee
invoke scss
create app/assets/stylesheets/api/tasks.scss

※コントローラのコード割愛

app/views/api/tasks/index.json.jbuilder作成

json.set! :tasks do
  json.array! @tasks do |task|
    json.extract! task, :id, :name, :is_done, :created_at, :updated_at
  end
end

app/views/api/tasks/show.json.jbuilder作成

json.set! :task do
  json.extract! @task, :id, :name, :is_done, :created_at, :updated_at
end

db/seeds.rbの作成

3.times { Task.create!(name: 'Sample Task') }
2.times { Task.create!(name: 'Sample Task', is_done: true) }

DB適用

$ rails db:seed

※ここでAPIの取得ができなかったのでこちら参考

app/controllers/api_controller.rb作成

class ApiController < ActionController::API
end

app/controllers/api/tasks_controller.rbの編集

class Api::TasksController < ApplicationController
# class Api::TasksController < ApiController # 結果どっちでも問題なさげ。
  def index
    @tasks = Task.order('updated_at DESC')
    render json: @tasks
  end

確認

$ curl localhost:3000/api/tasks
[{"id":5,"name":"Sample Task","is_done":true,"crea~~~~~,

👆とりあえずAPIサーバーの構築はできました◎

躓いた点

✅JSONの取得

以下でエラー

undefined local variable or method `json'

json.builderではなくjson.jbuilderでした。。。💦

コントローラ編集

class Api::TasksController < ApplicationController
# class Api::TasksController < ApiController
  # GET /tasks
  def index
    @tasks = Task.order('updated_at DESC')
    # render json: @tasks
  end

👆index.json.builderを参照するようにする。

いけました◎

参考:Railsのjbuilderの書き方と便利なイディオムやメソッド

✅POSTできない

※未解決

$ curl -X POST localhost:3000/api/tasks -d 'task[name]=fugafuga'

よく使うcurlコマンドのオプション

Reactを使う場合

ReactをRailsと共に使う方法

Gem

gem 'react-rails'
gem 'webpacker'

インストール

$ bin/bundle
$ rails webpacker:install // Vueを入れている場合conflictするのでY
$ rails webpacker:install:react
$ rails generate react:install

app/assets/javascripts/components/Hello.jsx作成

$ mkdir app/assets/javascripts/components/
$ touch app/assets/javascripts/components/Hello.jsx

編集

var HelloMessage = React.createClass({
  render: function() {
    return (
      <h1>Hello {this.props.name}!</h1>
    )
  }
});

views/index.html.erbの編集

<%# <%= javascript_pack_tag 'hello_vue' %> %>
<%= react_component('HelloMessage', name: 'Mike') %>

👆表示されず。。。

Vueと同じプロジェクトで作成しちゃったからか。。。

👇以下のように、別々でアプリ生成するのが吉かもしれない。

3. Rails(API)アプリとReactアプリを別々に作成する。

最もスタンダードと言っても良い方法では無いでしょうか。
この方法では、RailsをAPIとして作成し、全く別のReactのアプリケーションを作成します。
以下の様な利点があります。

  • Railsの問題はRailsで、Reactの問題はReactでと完全に別々で対処できる。
  • Reactアプリケーション以外にもモバイルアプリなど、他のクライアントにも対応することができるので多様な使い方ができ、よりスケールしやすい。

この方法ではRailsとReactアプリを別々で作成し、RailsがJSON化した情報を送り、クライアント側がリクエストで受け取る構造をとりますのでそれぞれの作り方は以下を参考にしてください。

Rails5で超簡単API
Reactチュートリアル

また、サンプルとして Rails + React + Docker + GraphQL を組み合わせて設計したアプリを作成しました。
ディレクトリ構成等で参考になればと思います。

rails s 時のデフォルトのポート番号を変更する ※ポート番号変更も調べたら用意。

メモ

axiosのインストール

$ yarn add axios

application_controller.rbに以下を追加

protect_from_forgery with: :exception

コメントを残す