Nuxt.jsの基礎勉強-firebaseと連携したToDoアプリ1-

はじめに

今回はグーグルが運営しているデータベースであるfirebaseとNuxt.jsのアプリケーションを連携させることを勉強した。 長くなると思うので記事を2つに分けて投稿します。

firebaseの環境設定

firebaseでプロジェクトを作成

  • firebaseでアカウント登録をしてCloud Firestore のデータベースをテストモードでプロジェクトを作成する。
  • 設定からプロジェクトIDを取得する。

firebaseとvuexfireと@nuxtjs/dotenvをインストール

$ npm install --save firebase
$ npm install --save vuexfire
$ npm install --save @nuxtjs/dotenv
  • 上記をインスコしたらpackage.jsonを開いてdependenciesに上記全部が記述されていることを確認する。

~/plugins/firebase.jsにfirebaseをimportする

import firebase from 'firebase'

const config ={
    projectId: process.env.FIREBASE_PROJECT_ID
}

if(!firebase.apps.length){
    firebase.initializeApp(config)
}

export default firebase

@nuxtjs/dotenvを利用して環境変数を使用する

  • @nuxtjs/dotenvを有効化するためにnuxt.config.jsのmodules部分に以下を記述
  /*
  ** Nuxt.js modules
  */
  modules: [
    '@nuxtjs/dotenv'
  ],
  • ~/.envを作成
FIREBASE_PROJECT_ID = 'Your firebase project id'
  • ~/.gitignoreにて~/.envを記述
.env

storeの設計

vuexfireの設定

  • vuexfire#usageにも記述されているがvuexfireは~/store/index.jsにてmutationsを作る必要があるので~/store/index.jsに以下を記述
import { vuexfireMutations } from 'vuexfire'

export const mutations = {
    ...vuexfireMutations
}

todos.jsにてfirebaseとvuexfireを取得して使う

  • pluginからfirebaseをimport
  • 同じくvuexfireもimport
  • firebaseをdbに格納 (今回はfirestoreを用いたからこの綴りになる)
  • 初期化したfirebaseにvuex内のデータであるtodosを格納
  • firebaseに渡す値todosを定義
  • vuexfireのusageにもある通りにActionを記述
  • init:でfirebaseを初期化
  • add:で入力値がある場合にtodosRefに夫々の値を格納している
import firebase from '~/plugins/firebase'
import { firestoreAction } from 'vuexfire'

const db = firebase.firestore()
const todosRef = db.collection('todos')

export const state = () => ({
    todos: []
})

export const actions = {
    init: firestoreAction(({bindFirestoreRef}) => {
        bindFirestoreRef('todos', todosRef)
    }),
    add: firestoreAction((context, name) => {
        if(name.trim()){
            todosRef.add({
                name: name,
                done: false,
                created: firebase.firestore.FieldValue.serverTimestamp()
            })
        }
    }),
          (以下略)

~/page/todos.vueに入力フォームの作成

textareaのフォームを作成して、submitを用いてデータの送信をサーバーに送る機能を作成。

  • template部分の記述
<template>
  <div class="form">
    <form v-on:submit.prevent="add">
      <input v-model="name">
      <button>Add</button>
    </form>
  </div>
</template>
  • script部分の記述
export default {
    data: function(){
        return {
            name: '',
            done: false
        }
    },
    created: function(){
        this.$store.dispatch('todos/init')
    },
    methods: {
        add(){
            this.$store.dispatch('todos/add', this.name)
            this.name = ''
        },

終わりに

抜けが無ければ上記まででfirebaseに入力したテキストデータとサーバーのタイムスタンプとfalseの値を投げるプログラムになる。

このコードは写経しながら書いたコードだったが後から読みながら公式ドキュメントを追ったりすることで、書いたコードの意味や作業の確認ができてよかったと思う。

次回はこのプログラムの続きを上げていきます。

Nuxt.jsの基礎勉強-カウンターアプリを作成-

はじめに

今回はカウンターアプリを作ることでvuexの知識を整理をした。

github.com

カウンターアプリの実装

storeの作成

  • モジュールモードを用いてストアを設計
  • stateにはデータの初期状態を記述
  • mutationsにデータの操作を記述
  • actionsにmutationの読み込み操作を記述
export const state = () =>({
    count: 0
})

export const mutations = {
    countUp: function(state, payload){
        state.count += payload
    },
    resetCount: function(state, payload){
        state.count = payload
    }
}

export const actions = {
    countUpAction: function(state, payload){
        state.commit('countUp', payload)
    },
    resetCountAction: function(state, payload){
        state.commit('resetCount', payload)
    }
}

コンポーネントでカウンターアプリを作成

  • 今回はアクションを介してミューテーションからストアの操作を行なったので、dispatchを使ってデータの送信をActionに送る。
<template>
    <section class="container">
        <p>
            {{ $store.state.counter.count }}
            <button @click="$store.dispatch('counter/countUpAction', 1)">+1</button>
            <button @click="$store.dispatch('counter/resetCountAction', 0)">reset</button>
        </p>

    </section>
</template>

ページでコンポーネントを表示

<template>
    <section class="container">
        <counter />
        <page />
    </section>
</template>

<script>
import counter from '~/components/counter.vue'
import page from '~/components/page.vue'
export default {
    components: {
        counter,
        page
    }    
}
</script>

終わりに

実際に自ら考えて作ってみることで、storeやcomponentsの記述の仕方を再学習するいい機会になった。

Nuxt.jsの基礎勉強-vuexの使い方について-

はじめに

今回はvuexを用いたデータの扱いについて学習したので纏めておく。

vuexとは

vue.jsを用いたアプリケーションで扱うデータの状態管理を行うツールのことです。

vuexを用いたデータを呼び出し

~/store/index.jsというファイルを作成し、vuexをimportして扱えるようにする。その後以下のように記述することで扱うことができる。

import Vuex from 'vuex'

const createStore = () => {
    return new Vuex.Store({
        state: function(){
            return{
                message: 'Hello Vuex'
            }
        }
    })
}

export default createStore

上記で定義したデータを呼び出すにはコンポーネントにて$storeを呼び出すことで出力することができる。

<template>
    <section class="container">
        <div>
            <p>{{ $store.state.message }}</p>
        </div>
    </section>
</template>

ミューテーションを用いたデータ操作

vuexを用いたデータの状態管理ではview側から直接的なデータ操作を行わずにミューテーションを介したデータ操作をする必要がある。

その理由として、データ管理を行う上でview側からの予期しない操作の防止やデータのバグが何処からきているのかを明確にし、アプリケーションのメンテナンス性向上に貢献することがあげられます。

基本的なmutation構文

基本的な記述の仕方は~/store/index.js内にmutationsを作ってその中に処理を記述します。

    return new Vuex.Store({
        state: function(){
              (略)
        },
        mutations: {
            updateMessage: function(state){
                state.message = 'Update Message'
            }
        }
    })

呼び出しは$store.commit('呼び出すミューテーション')

<p v-on:click="$store.commit('updateMessage')">
  {{ $store.state.message }}
</p>

mutationの値渡し

~/store/index.js側では第二引数を設定することで外部から値を受け取ることができる。

        mutations: {
            payloadMessage: function(state, payload){
                state.message = payload
            }
        }

コンポーネント側では第二引数として渡したい値を記述します。

<p v-on:click="$store.commit('payloadMessage', 'this is payload')">
  {{ $store.state.message }}
</p>

actionを介したmutationの扱い方

~/store/index.js側でactionを定義し、action側からミューテーションを呼び出すように記述します。

        mutations: {
            payloadMessage: function(state, payload){
                state.message = payload
            }
        },
        actions: {
            payloadMessageAction(context, payload){
                context.commit('payloadMessage', payload)
            }
        }

コンポーネント側ではdispatch関数を用いて、第一引数を呼び出すアクション名にし、第二引数を渡したい値とすることで記述できます。

<p v-on:click="$store.dispatch('payloadMessageAction', 'this is dispatch')">
  {{ $store.state.message }}
</p>

モジュールモードでの開発について

今までの記述の仕方はクラシックモードといって~/store/index.js内に一括管理する方法です。しかし、大規模アプリを作成する場合だと一括管理した場合、storeの記述が肥大化し管理が難しくなる可能性があります。

そこで、複数のファイルでstoreの管理を行うモジュールモードの記述をここでは記述していきます。

今までのコードをモジュールモードへ

モジュールモードで管理する場合は~/store/index.jsを作成せずにその他の名前でファイルを作成することで出来ます。

今回は~/store/hello.jsという風にファイルを作成し、以下のように各状態を関数型で定義していくことで、クラシックモードからモジュールモードに書き換えが完了します。

export const state = () => ({
    message: 'Hello Vuex'
})

export const mutations = {
    updateMessage: function(state){
        state.message = 'Update Message'
    },
    payloadMessage: function(state, payload){
        state.message = payload
    }    
}

export const actions = {
    payloadMessageAction(context, payload){
        context.commit('payloadMessage', payload)
    }
}

呼び出すときは、storeのモジュール名をコンポーネント内に表記することで出力することができます。

<p v-on:click="$store.commit('hello/updateMessage')">
    {{ $store.state.hello.message }}
</p>
<p v-on:click="$store.commit('hello/payloadMessage', 'this is payload')">
    {{ $store.state.hello.message }}
</p>
<p v-on:click="$store.dispatch('hello/payloadMessageAction', 'this is dispatch')">
    {{ $store.state.hello.message }}
</p>

終わりに

今回は実際にvuexを触ることで、vuexを用いた状態管理の大まかな概要を学ぶことができた。

Nuxt.jsの基礎勉強-ファイル構造の理解を深める-

はじめに

前回Nuxt.jsを勉強した際にはファイル構造や知識の追加だけだったので今回は実際に動かしてみたので行なったことについて纏めていく。

今回勉強した内容は以下のリポジトリにあげております。 github.com

componentsとpageについて

この二つがMVCのVに相当する部分になり、コンポーネントと各ページの出力を担うvueファイルを夫々纏めて管理することができる。

  • componenntsの基本構文は以下のように記述する
<template>
  <div class="Hello">
    Hello Nuxt.js
  </div>
</template>

<script>
export default { }
</script>>

<style>
.Hello {
  color: brown;
}
</style>
<template>
  <section>
    <hello />
  </section>
</template>
<script>
import hello from '~/components/hello.vue'

export default {
  components: {
    hello
  }
}
</script>

このように記述することで、ページ内にhelloコンポーネント内の記述がpage側で処理されてHello Nuxt.jsを出力することができる。

デフォルトのページデザインを弄る

layoutsについて

layouts/default.vue内のコードを弄ることでデフォルトのデザインを変えることができます。

<template>
  <div>
    <div class="header">
      <h1 class="header">This is First Nuxt.js</h1>
    </div>

    <Nuxt />
  </div>
</template>

<style>
.header{
  color: #fff;
  background-color: black;
}
~略~

上記のように記述することでヘッダーを全てのページのデフォルトとして付け足すことができる。

<Nuxt />が各ルートで呼ばれるページを出力する場所なので、これを消すと各ページの中身が消えてしまうので注意が必要。

nuxt.config.js

ここではアプリ内に使う外部ツール等の設定やHTMLの<head>記述を纏めています。公式参照

今回はテスト的にGoogle Fontsを使うようにコードを記述してみます。

  • nuxt.config.js
  head: {
    ~中略~
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Sriracha&display=swap'}
    ]
  },
  • layouts/default.vue
html {
  font-family: 'Sriracha', cursive;
~中略~
}

とすることで、デフォルトのフォントが変更される。

アプリのルートについて

ルート割り当てについて

アプリのルートは~/page/に入っているvueファイルの名前によって自動的に作られ、同名のvueファイルと関連付けがされます。

  • 例1) ~/page/index.vueとすると/が自動的に作られる
  • 例2) ~/page/second-pageとするとsecond-pageが割り当てられる

同様に階層を深くしたりしても自動的にその階層をルートとして割り当ててくれる。

ページ遷移について

Nuxt.jsではvue-routerを用いてページ遷移を行うので<router-link>タグを使うことで遷移ボタンを作成できる。

<template>
    <section>
        <router-link to="/">Top</router-link>
        <router-link to="second-page">second-page</router-link>
    </section>
</template>>

assetsについて

ここに画像ファイル等を置くことで管理しやすくしている。

終わりに

今回は以前勉強したディレクトリ構造からより理解を深めるために練習用のプロジェクトを作って使ってみることでNuxt.jsの概要をつかむことができたと思う。

次回はvuexを用いたデータ操作について勉強しようと思う。

環境変数をHerokuに設定した話

はじめに

前回の記事でAPIの変更を行なったRailsアプリがHerokuではerrorを出していたので、それについて問題解決をしてRailsアプリを動く状態にした。

daily-weather-app.herokuapp.com

status=500 errorについて

ローカルではしっかり動いたrailsアプリがHerokuにあげて動作させるとエラーを出したのでサーバーログを見ることに。

$heroku logs --tail

サーバーのログをみながらアプリの方を動かしていたら検索ボタンを押してAPIリクエストをするタイミングでステータス500エラーが出ていることに気づいた。 ここから考えられるエラーの理由は私の中では以下の3パターンです。

  1. データベースのデータが間違っている
  2. データベースのデータとRailsアプリが繋がっていない
  3. ENVを用いた環境変数がHeroku側でうまく適応できていない (ここに気づかなくてかなり詰んだ)

データベース関連の問題について

データベース関連の問題については私の場合、アプリ側でデータを追加する操作をしていないためサーバー側に重要なデータがないので、全てリセットして再構築することにしました。

heroku上のDBをリセットする

ENVを用いた環境変数がHeroku側でうまく適応できていない

データベース関連については片づいたはずなのにうまく起動しなかったため更にステータス500のみのエラーログについて考えることにしました。

ステータス500エラーというのは、"サーバー側のプログラムが実行できているがアクセスに失敗している状態"の事で、それについて思い当たる節を考えていった結果、環境変数をENVで定義している事でした。

なのでHeroku側にも環境変数を登録してあげれば動くのではないかと考え設定しみました。

  • Herokuサイトで該当アプリのプロフィールを見る
  • settingのConfig Varsを開くと登録できる

設定すると無事動きました。

参考サイト - Herokuで本番環境の環境変数(config vars)を.envファイルで設定する

終わりに

ENVを使った影響で本番環境が動いていないということに気づくまで結構長い時間詰んでたので、うまく動いてくれて安心しています。

Railsで作った天気アプリのAPIを変更した話

はじめに

今回はRailsで作った天気アプリで使っていたlivedoor さんの天気APIがサービス終了していたので、APIの取得先をopenweathermapさんに変更することにした。

github.com

openweathermapの利用登録

  1. openweathermapさんにてアカウント登録をする
  2. メールが届くのでリンクを踏んでアカウントの有効化
  3. メール宛にAPIキーが届きます(確かサイト内の自身プロフィールでも確認できます)
  4. APIキーが届いたら有効化されるまでにタイムラグがあるので待ちます

データの状態

こちらの記事がわかりやすかったのでここを参考にデータをいじってみた。

5日間天気予報(Call 5 day / 3 hour forecast data)の値一覧

require "net/http"
require "uri"
require "json"

API_KEY = "YOUR_KEY"
id = 1856035
uri = URI.parse("http://api.openweathermap.org/data/2.5/forecast?id=#{id}&appid=#{API_KEY}")
json = Net::HTTP.get(uri)
result = JSON.parse(json)

p result["city"]["name"]
p Time.at(result["list"][0]["dt"])
p Time.at(result["list"][8]["dt"])

上記コードのログ

"Tokyo"
2020-08-10 18:00:00 +0900
2020-08-11 18:00:00 +0900

RailsアプリでAPI取得を変更

元々あったAPIから得たjsonのデータ構造や名前などの違いを先ほど作ったコードで生のデータをいじりながら欲しいデータを取得できるように記述を変更していく。

seedデータを変更

アプリの使用上データベースに検索に用いるidを登録しているため、以前の仕様のままのデータベースを新しい仕様のデータベースに変更する。

seed内のコードを書き換えたらテーブルを一新してシード値を埋め込みました。

$rails db:migrate:reset
$rails db:migrate
$rails db:seed

I18nで日本語表示にする

生データのままだと英語で天気情報が返ってきたので、I18nを用いて得られた生データを日本語表示にして出力する様にした。

背景を変更

生データの使用上背景を変更するプログラムが正常に動作しなかったためapp/view/weather/_template.html.erb内の記述を変更

gitにあげる前にAPI_KEYを隠す

gitにあげる前にAPI_KEYを隠す必要があったので、dotenv-railsを使用した。

  • Gemfileにgem 'dotenv-rails'を追加して$bundle installする。

  • ~/.envファイルにAPI_KEYを記述

WEATHER_API_KEY=YOUR_API_KEY
  • ~/.gitignoreに.envファイルを弾く様に記述
.env

終わりに

今回はやることが多かったので、その中でも大まかな流れだけを説明しました。

APIに依存するアプリケーションのメンテナンスの大変さを身にしみて感じる機会になった。

Nuxt.jsの基礎勉強~ create-nuxt-appでプロジェクトの作成やファイル構造~

はじめに

今回はVue.jsのステップアップとしてNuxt.jsの勉強を行なったので、それについてまとめていこうと思う。

npmのinstall

npmが入ってなかったのでnpmの環境設定をした。(詳しくは以下の記事に記載しました) - npxコマンドを使うためにNode.jsをインストールした話

create-nuxt-app を用いたプロジェクトの作成

新規プロジェクトを立ち上げる時の質問

質問 意味
Project name 今回作るプロジェクト名-基本そのままでいい-
Programming language: 扱う言語-JavaScriptを選択-
Package manager: 扱うパッケージ-今回はnpmを選択-
UI framework: 扱うUI フレームワーク -今回はnone-
Nuxt.js modules: 扱うモジュール -今回はaxios-
Linting tools: コードチェックするためにEsLintを指定
Testing framework: テストに扱うフレームワークを指定
Rendering mode: レンダリングモードの選択-Vue.jsやNuxt.jsのみで作る予定ならUniversal-
Deployment target: デプロイする環境を設定
Development tools: 開発に使うツールを設定

ファイル構造

大まかなファイル構造以下の様なっている。特に重要だと思うディレクトリについては別途説明する。

.
├── README.md
├── assets
├── components
├── layouts
├── middleware
├── node_modules
├── nuxt.config.js
├── package-lock.json
├── package.json
├── pages
├── plugins
├── static
└── store

assets

スタイルシートや画像を管理するディレクト

components

componentを書いたファイルを管理するディレクト

pages

viewを作るファイルを保管する場所で、ここで作ったファイルによってパスが自動に生成される。

例) index.vue だと /のページのviewに該当し、hoge.vueだと./hogeに該当する

plugins

外部からインストールしたプラグインを管理しておくディレクト

store

vuexを用いてデータ操作を行う場合の操作を記述するソースを管理しておくディレクト

終わりに

今回はNuxt.jsのディレクトリ構造について勉強したので、次回からは実際に触っていこうと思う。