Rails6 Vueの連動方法(環境構築から)


##はじめに
Dockerを用いてRails,Vue,Posgre環境下で開発したいなと思った時に、
Rails,Vueの環境作りに手こずりましたので自分のメモとして保存します。

##この記事で分かること
・Rails6とVueとPostgresのDocker環境が構築できる
・RailsとVueの連動ができる
・PryにてインスタンスとDBの操作ができる

##環境
MacOS Mojave
Ruby 2.6.4
Rails 6.0.3.3
Vue 2.6.12
Webpack 4.44.2
yarn 1.22.5
Docker 2.3.0.5
VScode

##Githubのリンク

僕のGithubのDocker-Start-Kitです。よろしければご活用ください。
[Whiro0501/Docker_Rails6_Vue](https://github.com/Whiro0501/Docker_Rails6_Vue)


##Docker環境をMacに構築
ターミナルを開く
mkdirで任意の名前のディレクトリを作成
cdで作成したディレクトリに移動
code.でVScodeを開く

```terminal:terminal
mkdir qiita
cd qiita
code .
```



VScodeが起動
VScode上のターミナルで作業していくので
ターミナルが起動していなければ⬆︎+Control+@でターミナルを開く


VScodeのターミナル上で以下コマンドを入力してリモートリポジトリのファイルをローカルにコピー


```VScode:VScode
git clone https://github.com/Whiro0501/Docker_Rails6_Vue.git
```

cdでDocker_Rails6_Vue/ディレクトリに移動

```VScode:VScode
cd Docker_Rails6_Vue/
```

以下コマンドを実行してDockerイメージをビルド

```VScode:VScode
docker-compose build
```


以下を実行して、必要なノードモジュールを取得

```VScode:VScode
docker-compose run web yarn install --check-files
```


以下を実行して DB（Postgres)を作成

```VScode:VScode
docker-compose run web rake db:create
```

別のターミナルを開く
以下を実行してレールズアプリケーションを起動

```VScode:VScode
#別ターミナルが億劫なら、docker-compose up -dでも良い 
docker-compose up
```

さらに別のターミナルを開く
Viewを更新するたび毎回コンパイルが発生し、時間がかかるため以下を実行

```VScode:VScode
docker-compose exec web ./bin/webpack-dev-server
```

Webブラウザで以下にアクセス

```Webブラウザ:Webブラウザ
http://localhost:3000
```



Railsアプリケーションが起動することを確認

![スクリーンショット 2020-09-23 20.42.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406910/cd247cd6-a71f-b40a-f040-f50f90371a32.png)


#VueとRailsの連動ってどうやるの？

初期構築時点ではRailsとVueが連動されておりませんので連動させていく。

以下でhomeコントローラを作成する(コントローラー名はなんでも良い)。

```VScode:VScode
docker-compose exec web rails g controller home index
```

index.html.erbが作成

```rb:index.html.erb
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
```

以下ファイルに"root to:  'home#index'"を追加

```rb:routes.rb

Rails.application.routes.draw do
  root to:  'home#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

```

Webブラウザで以下にアクセス

```Webブラウザ:Webブラウザ
http://localhost:3000
```

まずはindex.html.erbに記述されている内容が表示

![スクリーンショット 2020-09-23 21.07.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406910/f71a55b9-4bac-6590-cfb2-1eb7f7dfaa91.png)

Rails側で下地ができたので、次にVueとの連動の設定
app.vueの初期設定

```vue:app.vue
<template>
  <div id="app">
    <p>{{ message }}</p>
  </div>
</template>

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

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

```

hello_vue.jsの初期設定

```javascript:hello_vue.js
import Vue from 'vue'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)

  console.log(app)
})
```

app.vueが単一ファイルコンポーネントであり、
hello_vue.jsにオブジェクトとして渡される。
それをindex.html.erbに表示させるよう設定する。

index.html.erbを以下の通り設定

```erb:index.html.erb
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

<%= javascript_pack_tag 'hello_vue.js' %>
<%= stylesheet_pack_tag 'hello_vue.js' %>

```

Webブラウザで以下にアクセス

```Webブラウザ:Webブラウザ
http://localhost:3000
```

Vueとの連動が完了!!

![スクリーンショット 2020-09-23 21.23.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406910/07f2813c-3200-e6f3-215d-edd83000240f.png)


##Githubののファイルの説明

[Whiro0501/Docker_Rails6_Vue](https://github.com/Whiro0501/Docker_Rails6_Vue)
まず上記リンクのGithubの状態から説明する
端的に説明すると以下2つを設定した後の状態となる
従ってRails6とVueとPostgresが使用できる環境を整えることができるという理屈である。

```VScode:VScode
docker-compose run web rails new . --force --database=postgresql --webpack=vue
```
加えて上記の状態だとPostgresがうまくRailsと連動できないため以下のように設定する。
こちらも公式ドキュメントを参考とした。

```database.yml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test


production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
```


###Dockerfile

公式ドキュメントのベストプラクティスを参照にした。
DockerはFROM, RUN, COPY毎にレイヤーが作成されるため
RUNやCOPYはできるだけまとめると少ないレイヤーで収めることができるとのこと。

```Dockerfile:Dockerfile
FROM ruby:2.6

# `apt-get install yarn`とするとエラーになる
# プロジェクトに必要なツールをインストール
# &&で繋げてコマンドを実行することによりレイヤーを1つとする
#apt-get update と apt-get installは同一RUN上で行う(分けると最新版を使用できない)
#RUNはイメージの作成次に実行(CMDはコンテナ起動時に実行)
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
    apt-get update -qq && apt-get install -y nodejs postgresql-client vim && \
    apt-get install -y yarn

# ディレクトリの作成
RUN mkdir /myapp

# 作業ディレクトリの指定
#RUN ,  COPY,  ADD 命令のみレイヤを作成するためWORKDIRは気にしなくて良い
# 絶対パスとする
WORKDIR /myapp

# Gemfileが更新された時のみ、レイヤを再構築
#先にプロジェクト全体をコピーしないのはレイヤーを分けるため
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# ライブラリの依存関係をインストール
RUN bundle install

# プロジェクト全体をコピー(Gemfile/Gemfile.lockはコピーされない)
COPY . /myapp

#コンテナを起動する毎に実行されるスクリプトを追加
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

#コンテナの公開ポート番号の指定
EXPOSE 3000

#指定しなければコンテナ起動時にデフォルトで実行する処理
#Dockerfile では CMD 命令を 1 つしか記述できない
#ENTRYPOINT 命令に対するデフォルト引数としてCMDを使用可能
CMD ["rails", "server", "-b", "0.0.0.0"]
```

###docker-compose
docker-compose.ymlもDocker公式ドキュメントを参考にした。

```docker:docker-compose.yml
version: '3'
services:
    db:
        # DBにpostgresを使用
        image: postgres
        # ホストの./tmp/dbと/var/lib/postgresql/dataを同期させる
        volumes:
            - ./tmp/db:/var/lib/postgresql/data
        # 環境変数の指定
        environment:
            POSTGRES_PASSWORD: password
    web:
        build: .
        # コンテナ起動時にserver.pidを削除し、rails sを実行する
        command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
        # ホストのカレントディレクトリをコンテナの/myappと同期させる
        volumes:
            - .:/myapp
        # ホストとコンテナ間をポートフォワードする
        ports:
            - '3000:3000'
        # サービス間の依存関係
        depends_on:
            - db
        # Docker環境でByebugを使用
        stdin_open: true
        tty: true
```

###Gemfile
Gemfileに関してはデフォルトで入っているもの主となる。
追加したパッケージはコメントしているため不要であれば削除して構わない

```Gemfile:Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }


ruby '2.6.6'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3', '>= 6.0.3.3'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# Use Puma as the app server
gem 'puma', '~> 4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  #デバックツールの導入
  gem 'pry-rails'
  gem 'pry-byebug'
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  #自動補完用ツールの導入
  gem 'solargraph'
  #静的コード解析ツールの導入
  gem 'rubocop'
  gem 'rubocop-rails'
  #erbのフォーマットツールの導入
  gem 'htmlbeautifier'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
```

###package.json
package.jsonについてはvue-routerとvuexを使いたいため追加している
Vuetify等、UIフレームワークを使用したいようであれば追加する。

```package.json:package.json
{
	"name": "myapp",
	"private": true,
	"dependencies": {
		"@rails/actioncable": "^6.0.0",
		"@rails/activestorage": "^6.0.0",
		"@rails/ujs": "^6.0.0",
		"@rails/webpacker": "4.3.0",
		"turbolinks": "^5.2.0",
		"vue": "^2.6.12",
		"vue-loader": "^15.9.3",
		"vue-template-compiler": "^2.6.12",
		"vue-router": "^3.0.1",
		"vuex": "^3.0.1"
	},
	"version": "0.1.0",
	"devDependencies": {
		"webpack-dev-server": "^3.11.0"
	}
}
```


##Railsでデバッグする

VScode上のターミナルを開く
以下をターミナルで実行

```VScode:VScode
docker-compose exec web rails console
```

pry が起動

```VScode:VScode
[1] pry(main)> 
```

postコントローラーを作成

```
docker-compose exec web rails g controller post index
```

post_controller.rbを修正

```rb:post_controller.rb
class PostController < ApplicationController
  def index
    @post = Post.all
  end
end

```

postのモデルを作成

```VScode:VScode
docker-compose exec web rails g model post name:string age:integer
```
DBにモデルを反映させる

```VScode:VScode
docker-compose exec web rails db:migrate
```

index.html.erbを以下に書き換え

```erb:index.html.erb
<%= @post.name %>
<%= @post.age %>
```

routes.rbを以下に修正

```rb:routes.rb
Rails.application.routes.draw do
  root to:  'post#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
```

pryでPostモデルのインスタンスを作成


```VScode:VScode
@post = Post.new
=> #<Post:0x00005589bc4beb78 id: nil, name: nil, age: nil, created_at: nil, updated_at: nil>

#まだnameやageにはデータを入れていない
#DBに保存もされていない
Post.all
=>   Post Load (2.2ms)  SELECT "posts".* FROM "posts"
[]

#DBにインスタンスを保存する
@post.save
   (0.7ms)  BEGIN
  Post Create (5.9ms)  INSERT INTO "posts" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2020-09-23 13:06:47.962085"], ["updated_at", "2020-09-23 13:06:47.962085"]]
   (3.1ms)  COMMIT
=> true

#もう一度Post.allをしてデータをDBから取得すると保存したインスタンスが呼び出される
Post.all
=>   Post Load (2.2ms)  SELECT "posts".* FROM "posts"
[#<Post:0x00005589bceec5f0
  id: 1,
  name: nil,
  age: nil,
  created_at: Wed, 23 Sep 2020 13:06:47 UTC +00:00,
  updated_at: Wed, 23 Sep 2020 13:06:47 UTC +00:00>]

#@postインスタンスにデータを入れてみる
@post.name = "Hiro"
=> "Hiro"

@post.age = "29"
=> "29"

#再び保存
@post.save
Post Update (4.0ms)  UPDATE "posts" SET "name" = $1, "updated_at" = $2 WHERE "posts"."id" = $3  [["name", "Hiro"], ["updated_at", "2020-09-23 13:10:26.486888"], ["id", 1]]
Post Update (2.0ms)  UPDATE "posts" SET "age" = $1, "updated_at" = $2 WHERE "posts"."id" = $3  [["age", 29], ["updated_at", "2020-09-23 13:10:56.785029"], ["id", 1]]
   (1.0ms)  COMMIT
=> true

#データが保存されている
Post.all
=>   Post Load (1.4ms)  SELECT "posts".* FROM "posts"
[#<Post:0x00007f1ddc7a77a8
  id: 1,
  name: "Hiro",
  age: 29,
  created_at: Wed, 23 Sep 2020 13:06:47 UTC +00:00,
  updated_at: Wed, 23 Sep 2020 13:10:56 UTC +00:00>]
```

Webブラウザで以下にアクセス

```Webブラウザ:Webブラウザ
http://localhost:3000
```

以下のようにDBからデータを取得できればOK

![スクリーンショット 2020-09-23 22.27.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406910/b9bfbb2b-2603-fa0d-8df9-8ddd88b1ac09.png)

####Binding.pryを試してみる

post_controller.rbを修正

```
class PostController < ApplicationController
  def index
    binding.pry
    ＠post = Post.all
  end
end

```

Webブラウザで以下にアクセス

```Webブラウザ:Webブラウザ
http://localhost:3000
```

以下の画面でフリーズする(正しい挙動)
![スクリーンショット 2020-09-23 22.30.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406910/5a724373-5120-9bbf-1745-92d690321591.png)


pryのターミナルに戻る

```
pry(main)> 
```

以上で、pryでデバッグする環境が整った


##参考
以下のサイトを参考にさせていただきました。
[Docker ドキュメント日本語化プロジェクト](https://docs.docker.jp/)
[クィックスタート: Compose と Rails](https://docs.docker.jp/compose/rails.html)
[Dockerfile のベストプラクティス](https://docs.docker.jp/engine/articles/dockerfile_best-practice.html)
[Webpacker の基本的な仕組み](https://numb86-tech.hatenablog.com/entry/2019/01/09/215714)
[Dockerを使って「Rails / PostgreSQL」の開発環境を作ろう！](https://opiyotan.hatenablog.com/entry/rails-tips-docker-development)