20
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RailsとVue.js(SPA)を「いいとこ取り」。API連携で開発するハンズオン。(その2:Vue編)

Last updated at Posted at 2020-03-07

この記事は その1:Rails編 の続きです。

何を作っているか

DBの操作と管理画面はRailsで作成しつつ、一般ユーザ向けの画面はSPAとかPWAにしたいというシーンは結構あるかと思います。既存アプリがRailsで動いているのを活かしながら、フロント側はSPA化するとか。基本はSPAなんだけど、管理画面はscaffoldでサクッと作って済ませたいとか。

そんなことを考えながら、このシリーズではRails(管理画面&API)Vue.js&Nuxt.js(SPA)という構成のアプリを、以下の役割分担で作っています。

Rails(View) Rails(API) Vue&Nuxt
コンテンツの表示(一般公開)
コンテンツの編集(管理者限定)

この記事では、Vue.jsとNuxt.jsでSPAの画面を作成し、Railsで作成したAPIと連携するところを掲載します。

アプリの題材はポートフォリオ。実はもうリリース済みです

Vue.js&Nuxt.js側の準備

SPAモードで作ります。
言語はJavaScriptを選択しました。

Vuetifyは最初は1.5系が入ってしまうので、2.0系に後から上げます。

###2020.3.14追記
1.5系が入ってしまうというのは勘違いだった可能性があります。

nuxt-community/vuetify-moduleのCHANGELOGによれば、2019−07−23時点でVuetify2に対応したと書いてありました。

追記時点ではすでにVuetify2系にアップデート済みなので確認できませんが、yarn listで確認を取っていればどのバージョンが入っているか確実に確認できたはずです。
ちなみに、追記時点はでvuetify@2.1.4でした。

###追記おわり


##環境

  • Vue.js 2.6.11
  • Nuxt.js 2.11.0
  • Vuetify 2.1.0
  • 開発環境はmacOS Mojaveです。1

前提

  • Nuxt.jsはローカルにインストール済み
  • Githubはアカウント取得済み

プロジェクト生成

「portfolio-vue」と言うプロジェクト名で進めます。

Nuxt公式に従います。
https://ja.nuxtjs.org/guide/installation/

console
$ yarn create nuxt-app portfolio-vue

この後の選択肢は、以下のようにしました。

console
? Project name portfolio-vue
? Project description shozzy's portfolio
? Author name shozzy
? Choose the package manager Yarn
? Choose UI framework Vuetify.js
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules Axios
? Choose linting tools Prettier
? Choose test framework Jest
? Choose rendering mode Single Page App
? Choose development tools jsconfig.json (Recommended for VS Code)

しばらく待ったのち、、、

🎉  Successfully created project portfolio-vue

  To get started:

	cd portfolio-vue
	yarn dev

  To build & start for production:

	cd portfolio-vue
	yarn build
	yarn start

  To test:

	cd portfolio-vue
	yarn test

✨  Done in 72.01s.

うまく行きました!

$ cd portfolio-vue
$ yarn dev

ブラウザから http://localhost:3000/ にアクセスします。

このような画面になれば成功です:tada: 2
スクリーンショット 2019-09-08 21.34.37.png

VSCodeで「Add Folder to Workspace...」から「portfolio-vue」を選択します。

(不要なはず)Vuetifyを2.0系にする

2020.03.14追記:前述の通り、この手順は不要と思われます。そのため、記載内容を折りたたみました。
yarn listで表示されるvuetifyのバージョンを確認しておきましょう。

以前の記載内容
Vuetifyのバージョンが1.5系なので、2.0系に先に上げておきます。

変更前

nuxt.config.js
   modules: [
     // Doc: https://axios.nuxtjs.org/usage
     '@nuxtjs/axios',
   ],

変更後

nuxt.config.js
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/vuetify',
    '@nuxtjs/axios',
  ],

Vuetify公式によれば、執筆時点3での最新はv2.1.4のようなので、そこまで上げておきます。
https://github.com/vuetifyjs/vuetify/releases

$ yarn add vuetify@2.1.4

念のため、Vuetify2.0で動作しているか確認しておきます。
方法は、デフォルトで生成されるindex.vueの中身をVuetify2.0から導入された「v-row」「v-col」を用いるように変更し、それがブラウザで正しく表示されるかを確認します。4

変更前

pages/index.vue
<template>
  <v-layout
    column
    justify-center
    align-center
  >
    <v-flex
      xs12
      sm8
      md6
    >
<!-- 中略 -->
        <v-card-title class="headline">
          Welcome to the Vuetify + Nuxt.js template
        </v-card-title>
<!-- 中略 -->
    </v-flex>
  </v-layout>
</template>

変更後

pages/index.vue
<template>
  <v-row
    column
    justify-center
    align-center
  >
    <v-col
      xs12
      sm8
      md6
    >
<!-- 中略 -->
        <v-card-title class="headline">
          Welcome to the Vuetify2.0 + Nuxt.js template
        </v-card-title>
<!-- 中略 -->
    </v-col>
  </v-row>
</template>

表示されたので、問題なさそうです。
スクリーンショット 2019-09-08 23.57.18.png

GitHubへ初期コミット

ここらでGithubにfirst commitしておきます。

$ git init
Reinitialized existing Git repository in /Users/shozzy/portfolio-vue/.git/

どうやら最初からgitもセットアップされていたようです。
git initしても害はなさそうなので、そのまま進めました。

もしGithubを使うのが初めてであれば、メールアドレスの設定が必要です。

設定済みのかたは飛ばしてください。 your-github-mailaddress の部分は、Githubから提供される「noreply」のメールアドレスか、外部公開されても問題のない(可能ならGithub用に作成した)メールアドレスを設定してください。外部公開されるので、くれぐれも通常使用しているメールアドレスは指定しないように。

参考:
過去記事1
過去記事2

$ git config --global user.email your-github-mailaddress

Githubのサイトへログインし、新しいリポジトリを作成します。
プライベートリポジトリでも問題ありません。

.gitignore はnuxtがいい感じに設定してくれているので、そのままでOKです。

$ git add .
$ git commit -m "first commit"
$ git remote add origin https://github.com/shozzy/portfolio-vue.git
$ git push -u origin master

ソース管理を開始できたので、ここから開発を進めていきます。
ブランチを切りつつチェックアウトしておきます。

$ git checkout -b create-pages

Nuxtのポートを変更

RailsもNuxtも、開発環境のポートがデフォルトでは3000です。
これでは同時に開発できないので、片方を変更する必要があります。
ここでは、Nuxtの方を8000番に変更しました。(http://localhost:8000/)

変更前

nuxt.config.js
export default {
  mode: 'spa',

変更後

nuxt.config.js
export default {
  server: {
    port: 8000,
  },
  mode: 'spa',

中身を作る

ここから中身を作っていきます。

※説明を最小限にするため、解説している内容と、キャプチャ画像の見た目が異なる場合があります。

productsページ

先に、実際にAPIを使うページから作っていきます。
productsはこれまでの作品を紹介するページです。
コンテンツはAPIから取得したものを表示します。

productsページはhttp://localhost:8000/products
コンテンツを一覧で取得するAPIはhttp://localhost:3000/api/contentsで用意してあります。バックエンドはRails。

以下のファイルを新規作成します。
最初は単純に、APIで取得したJSONをそのまま表示するだけの内容です。

pages/products.vue
<template>
  <div>
    {{ contents }}
  </div>
</template>

<script>
export default {
  async asyncData({ app }) {
    const contents = await app.$axios.$get('https://localhost:3000/api/contents')
    return { contents }
  },
}
</script>

、、、実は、これだとCORSエラーになります。
Nuxt側のOriginはlocalhost:8000ですが、Rails側のOriginはlocalhost:3000だからですね。
スクリーンショット 2019-10-18 12.19.31.png

CORS (Cross-Origin Resource Sharing) を出来るようにする

クロスオリジンでのアクセスには制限がかかっています。CSRFを防ぐために。

そこで、Rails側でgem 'rack-cors'を使ってNetlify側からのアクセスを許可します。

###Rails側
Rails側にrack-corsの設定を追加します。

Gemfile
gem 'rack-cors'
$ bundle install

ここでconfig/initializers/cors.rbの設定が必要になりますが、今回のRails環境はAPIモードではないので、このファイルは自動生成されません。なので、手動で作リます。

config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins Rails.application.config.permitted_origin
    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

許可する呼び出し元は、ローカルと本番環境で当然異なるので、これも環境変数で定義します。5

開発環境ではdotenv-railsを利用します。

Gemfile
group :development do
  #中略
  gem 'dotenv-rails'
end
.env
PERMITTED_ORIGIN = 'localhost:8000'
application.rb
    config.permitted_origin = ENV.fetch('PERMITTED_ORIGIN', 'http://localhost:8000')

これで、Vue側(localhost:8000)からのアクセスが許可されました。

###Vue側
ついでに、Vue側にも環境変数「API_BASE」を作成し、APIが存在するドメインを設定できるようにしておきます。
ローカルの開発環境と本番環境ではドメインが異なるためです。

ローカルではdotenvを用います。6

$ yarn add @nuxtjs/dotenv
.env
API_BASE=http://localhost:3000
nuxt.config.js
  env: {
    API_BASE: process.env.API_BASE,
  },

  buildModules: [
    '@nuxtjs/dotenv',
  ],

これで、コード中でprocess.env.API_BASEを用いて環境変数の内容を読み出せるようになりました。

pages/products.vue
<script>
export default {
  async asyncData({ app }) {
    const contents = await app.$axios.$get(process.env.API_BASE+'/api/contents')
    return { contents }
  },
}
</script>

###JSONをAPI経由で取得する
ようやく、JSONでデータを取得できるようになりました。:tada:

スクリーンショット 2019-10-18 12.30.12.png

見た目を整える

JSONのままではサイトとして公開できませんので、見た目を調整していきます。
各アイテムを表示するカード部分は繰り返し登場するので、コンポーネント化しました。

スクリーンショット 2019-12-01 19.21.58.png

7

pages/products.vue
<template>
  <div>
      <v-container fluid>
        <v-row row wrap>
          <v-col v-for="item in contents" v-bind:key="item.id" xs12 sm6 md4>
            <ProductCard v-bind:title="item.title" v-bind:content="item.detail"/>
          </v-col>
        </v-row>
      </v-container>
  </div>
</template>

<script>
import ProductCard from '~/components/ProductCard.vue'
export default {
  components: {
    ProductCard
  },
  async asyncData({ app }) {
    const contents = await app.$axios.$get('/api/contents')
    return { contents }
  },
}
</script>

コードを全て掲載すると長くなりすぎるので、詳細はGitHubにて。

まとめ

この記事では、コンテンツをREST API経由で取得し、SPAのサイト内で表示させるところまで作成しました。

次の記事(鋭意執筆中)では、本番環境へのデプロイを実施します。本番環境はNetlify+Herokuの組み合わせを想定しています。

推敲にはかなり時間をかけましたが、おかしいところがありましたら教えて頂けますと幸いです。

参考にしたWebサイト

執筆者の皆様、本当にありがとうございます!

  1. 大枚はたいて買ったAdobeCS6を使い続けたいから上げられない、、、(どこかで諦めるしかありませんが)

  2. 今回はVuetifyを採用したのでこの画面ですが、他のCSSフレームワークを選択した場合は、異なる見た目の画面になると思われます。

  3. この部分を書いたのは2019/10/16。公開までだいぶ時間があいてしまいました。。。

  4. もっとスマートな方法があるような気がしています。ご存知のかたいらっしゃいましたら、教えていただけると幸いです。

  5. 今回は完全にクローズドなAPIなのでアクセス元の制限をかけています。オープンなAPIなら制限なしもありえますし、特定のユーザだけに解放するようなAPIであればAPIキーでの認証になるはずです。

  6. 本番環境(Netlify)では "Environment variables" で定義しました。

  7. コンテンツ自体も編集しながら進めているので、JSONのキャプチャと見た目を整えた後のキャプチャでは内容が異なっています。

20
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?