よしたく blog

ほぼ週刊で記事を書いています

初心者に最適なCloud Functions for Firebaseの公式サンプル集

Cloud Functions for Firebaseについて調べていたら、公式のGitHubに非常に多くのサンプルがありましたので紹介します。

github.com

中には45本ものサンプルスクリプトがあるので眺めるだけで勉強になります。

2019/4/18に発表されたCloud Functions for Firebaseで定期実行できる機能のサンプルプログラムもありました。

github.com

以前、定期実行する機能はありませんでした。そのため自分はGoogle Apps Scriptsなどで代替したり、GCPと連携して実行するようにしたり、いろいろ工夫して実装している人がいました。

Cloud Functions for Firebaseの定期実行を軽く触ってみた感想ですが、そもそも料金のプランを無料から従量課金制にする必要があったりで実装の前段階でのハードルがあるような気がしました。

qiita.com

qiita.com

developers-jp.googleblog.com

Vue.jsでCSVを取り込んで表示する

今回はVue.jsでCSVファイルを取り込んで、そのまま画面に表示することをしたいと思います。

今回のソースは過去のツイート情報を表示することを想定しています。
全ツイート履歴をダウンロードする方法は公式を御覧ください。

help.twitter.com

全ツイート情報は、jsファイルでダウンロードできますが、JSONに拡張子を変更しそこからCSVに変更してください。自分は目的と違うところでつまづきたくなかったので次のサービスを利用しました。

convertcsv.com

<template>
  <div>
    <h1>CSVインポート</h1>
    <input @change="fileRead" type="file" id="file_input_expense" name="file_input_expense">
    <li v-for="worker in workers" v-bind:key='worker.id'>
        <a v-bind:href=worker.url target="_blank">https://twitter.com/yoshitaku_jp/status/{{ worker.id }}</a> <button v-on:click="delTweet(worker)" type="button" id="delTweet" name="delTweet">delTweet</button>
    </li>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      workers: []
    };
  },
  methods: {
    fileRead: function(e) {
      var _this = this;
      let file = e.target.files[0];
      let csv = [];
      let reader = new FileReader();

      reader.onload = function() {
        let lines = reader.result.split("\n");
        lines.forEach(element => {
          let workerData = element.split(",");
          let worker = {
            id: workerData[8],
            url: "https://twitter.com/yoshitaku_jp/status/" + workerData[8],
          };
          csv.push(worker);
        });
        _this.workers = csv;
      };
      reader.readAsBinaryString(file);
    }
};
</script>

ソースはほぼこちらを参考にさせていただきました。 https://qiita.com/WallyNegima/items/67a16915fbd77e2e0f03 https://qiita.com/tantai/items/5cf98364efa4a80324bd

参考先では次のように書かれていましたが、自分なりに模索していたら上記のような形になりうまくいきました。少しスッキリできてよかったです。

const loadFunc = () => {
  ///処理
};
reader.onload = loadFunc;

RailsとVueの環境構築

これまでVue.jsでいくつかサイトを作ったりしてきました。Firebaseを組み合わせたりして手軽に実装でき、まだまだ改良すべき点はありますが非常にいい成功体験となりました。次に作るものはバックエンド含めて自分で実装してみたいと思い、今回はRailsを選んで取り組んでいます。

今回は、RailsとVue.jsの環境構築についてです。

なお、RubyRailsはすでに導入されているものとします。 自分は次の環境で実施しました。

ruby 2.5.3
Rails 5.2.3

環境構築

rails new rails_vue_todo --api --webpack=vue

rails newをして作成します。今回はオプションに--api--webpack=vueを使います。

--api

--api をつけることで、普通にnewをするよりか少ないファイルで作成することができます。

  • 利用するミドルウェアを通常よりも絞り込んでアプリケーションを起動するよう設定します。特に、ブラウザ向けアプリケーションで有用なミドルウェア(cookiesのサポートなど)を一切利用しなくなります。
  • ApplicationControllerを、通常のActionController::Baseの代わりにActionController::APIから継承します。ミドルウェアと同様、Action Controllerモジュールのうち、ブラウザ向けアプリケーションでしか使われないモジュールをすべて除外します。
  • ビュー、ヘルパー、アセットを生成しないようジェネレーターを設定します。

railsguides.jp

--webpack=vue

--webpack=vue をつけることで、Webpackerを使う設定をいれることができます。Webpackerを使うと、JavaScriptプリプロセッサおよびwebpack を使う手間が省けるうえに、RailsJavaScriptアプリケーションのような形で管理できます。

--webpack=vuevueをつけることで、Yarnを使用してVueとその必要なライブラリを追加します。 サンプルコンポーネントはapp / javascriptでプロジェクトに追加されるので、すぐにVueを試すことができます。

--webpack=react にすることで、reactの設定を追加することもできます。

最後にwebpackerの導入とvueの導入をおこないます。

rails webpacker:install
rails webpacker:install:vue

起動

./bin/webpack-dev-server を実行してコンパイルをします。 Windowsの場合は、ruby ./bin/webpack-dev-server を実行します。

rails sでサーバを起動して、ブラウザで画面を確認できれば終了です。

今後は、素振りとしてTodoアプリの作成をおこなっていきます。

github.com

NetlifyCMSをGridsomeに適用する方法

yoshitaku-jp.hatenablog.com

以前の記事でGridsomeを使う設定をおこないました。今回はCMSを導入し使う設定をおこないます。使うCMSはNetlifyCMSです。

すでに海外の方が使える設定を公開していて参考にさせてもらいました。

ディレクトリとファイルの作成

YOUR_DIRRECYORYE/static/adminディレクトリを作成し、配下に2つのファイルを作成します。 index.htmlconfig.ymlです。

index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Content Manager</title>
</head>
<body>
  <!-- Include the script that builds the page and powers Netlify CMS -->
  <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
</body>
</html>

config.yml

backend:
      name: github
      branch: master # ブランチ名を記入します
      repo: yoshitaku-jp/challenge-every-month # 自分のリポジトリを記入します
    
    media_folder: "static/images/uploads" # YOUR_DIRRECYORYE/staticの配下に画像のアップロード先を指定します。
    public_folder: "/images/uploads" # The src attribute for uploaded media will begin with /images/uploads
    
    collections:
      - name: "blog" # Used in routes, e.g., /admin/collections/blog
        label: "Blog" # Used in the UI
        folder: "blog" # The path to the folder where the documents are stored
        create: true # Allow users to create new documents in this collection
        slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
        fields: # The fields for each document, usually in front matter
          - {label: "Layout", name: "layout", widget: "hidden", default: "blog"}
          - {label: "Title", name: "title", widget: "string"}
          - {label: "Publish Date", name: "date", widget: "datetime"}
          - {label: "Featured Image", name: "thumbnail", widget: "image"}
          - {label: "Body", name: "body", widget: "markdown"} 

YOURSITE/admin/ にアクセスする

次の画面が出れば成功です

f:id:yoshitaku_jp:20190331090709p:plain

参考サイト

dev.to

git rebase でマージコミットを表示する方法

git rebase でマージコミットを表示する方法

git rebase -i -p HEAD~~~-pオプションを付けることでマージコミットは表示できます。

なんで表示されないのかわからず、詰まってしまったのでメモを書いておきます

準備

masterブランチでコミットして、devブランチを作成しコミットし、またmasterに戻ってきてコミットをするところまでです。

mkdir sandbox-git
cd sandbox-git/
git init
touch master.txt
git add .
git commit -m "this is master"
git checkout -b dev
touch dev.txt
git add .
git commit -m "this is dev 1"
git checkout master
touch return-master.txt
git add .
git commit -m "this is return-master"

-pオプションなし

devブランチをマージして、-iオプションなしで表示してみます。

git merge dev
git rebase -i HEAD~~

f:id:yoshitaku_jp:20190324103830p:plain
-pがないと表示されない

-pオプションあり

devブランチをマージして、-iオプションありで表示してみます。

git merge dev
git rebase -i -p HEAD~~

f:id:yoshitaku_jp:20190324103906p:plain
-pがあると表示される

おしまい。

Railsの中間テーブルを経由してデータ取得ができなかったエラー

tl;dr

  • has_manyを使ってデータを取得したかった
  • has_manyには記述する順番がある

エラー内容

Cannot have a has_many :through association 'Hoge#fuga' which goes through 'Hoge#hoge_fuga' before the through association is defined.

発生の状況

ユーザが持っている本の一覧を中間テーブルを経由して取得したかった。 下記のコードを書いていた。

class User < ApplicationRecord
    has_many :books, through: :user_books
    has_many :user_books
end

解決策

Railsのバージョンが上がってから、has_many の順番が重要になったようで、順番を入れ替えたら解決した。

class User < ApplicationRecord
    has_many :user_books
    has_many :books, through: :user_books
end

参考

qiita.com

CircleCIのManual Approval機能を試した

CircleCIのManual Approval機能を触ってみました。 設定方法と注意点について記載しておきます。

公式サイトはこちら。

https://circleci.com/docs/2.0/workflows/#holding-a-workflow-for-a-manual-approval

設定ファイルの記述方法

大まかな枠組みを記述しました。

version: 2
jobs:
  build:
      # buildの処理
  deploy:
      # deployの処理
workflows:
  version: 2
  build_and_deploy:
    jobs:
      - build
      - approval-deploy:
          type: approval
      - deploy:
          requires:
            - approval-deploy

type: approval

type: approval を記述すると、そのjobがCicleCIの画面上で承認ボタンを押さなければならない部分になります。 承認ボタンを押すことで次に処理が進みます。 注意ですが、このtype: approvalを設定したjobsにはなにも記述しないのが正しいようです。

requires: - approval-deploy

後続の処理には、requires: - approval-deployを記述します。requiresは、指定されたjobsが終了したら自分自身を実行する設定になります。つまりこの場合は、「approval-deployjobsが終了したら、deployjobsを実行します」という意味になります。

type: approvalrequires: - approval-deployの2つを使うことで、承認ボタンを押さないとデプロイを実行できないフローが完成します。

画面上での流れ

CircleCI上での一連の流れのキャプチャを載せておきます。

f:id:yoshitaku_jp:20190306163822p:plain
build実行中

f:id:yoshitaku_jp:20190306163834p:plain
buildが実行終了したが、deployは走らない

f:id:yoshitaku_jp:20190306163843p:plain
approval-deployをクリックし、承認する

f:id:yoshitaku_jp:20190306163852p:plain
後続のdeployが実行される

おしまい。

Gridsomeでサイト作りを始めた

Vue.js製の静的サイトジェネレーターを見つけました。Gridsomeです。 最近よく聞くReact.js製のGatsbyと似たような構成のようです。

今回はサイトを作ってから、Netlifyにpushするまでを実施してみたいと思います。

環境構築

インストール

まずはnpmでインストールをおこないます。

npm install --global @gridsome/cli

プロジェクトを作成する

次にgridsome createコマンドでプロジェクトを作成します。そして、delelopコマンドを実行し開発用サーバを立ち上げます。

gridsome create gridsome-demo
cd gridsome-demo
gridsome develop

開発環境を立ち上げて確認

http://localhost:8080をブラウザで開くと、下の画面が表示されます。

f:id:yoshitaku_jp:20190303231612p:plain

ブログを書く準備

インストール

ファイルサービスを利用するために npm install --save @gridsome/source-filesystem を実行します。

Markdownで記述するために npm install --save @gridsome/transformer-remark を実行します。

設定ファイルを変更

gridsome.config.js で、先程インストールしたモジュールを有効にするため設定を変更します。

module.exports = {
  transformers: {
    remark: {
      externalLinksTarget: '_blank',
      externalLinksRel: ['nofollow', 'noopener', 'noreferrer'],
      anchorClassName: 'icon icon-link',
      plugins: [
      ]
    }
  },

  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'goal/*.md',
        typeName: 'GoalPost',
        route: '/goal/:year/:month/:day',
        remark: {
          plugins: [
          ]
        }
      }
    }
  ]
}

投稿内容を表示する

内容を用意する

gridsome.config.js のPathに書いたようにファイルを作成します。今回はgoal/post1.mdとし、中身を記述します。

---
title: はじめての内容だよ
date: 2019-03-03 01:00:00
description: "はじめての内容"
tags: "contents"
---

はじめての内容が入るよ

一覧を表示する

src/pages/index.vueを作成します。

<template>
  <Layout>
      <h1>Contents</h1>
      <div v-for="item in $page.allGoalPost.edges" :key="item.path" class="post">
        <h2>
          <g-link :to="item.node.path">{{ item.node.title }}</g-link>
        </h2>
        <dl>
          <dt>{{ item.node.date }}</dt><dd>{{ item.node.fields.tags}}</dd>
        </dl>
        <p>{{ item.node.fields.description }}</p>
        <div class="content" v-html="item.node.content" />
      </div>
  </Layout>
</template>

<page-query>
  query Home ($page: Int) {
    allGoalPost (page: $page) {
      edges {
        node {
          _id
          title
          date (format: "YYYY年MM月DD日 HH:mm:ss")
          fields {
            description
            tags
          }
          content
        }
      }
    }
  }
</page-query>

<script>
  export default {}
</script>

これでURLhttp://localhost:8080/にアクセスすると下の画像が表示されます。

f:id:yoshitaku_jp:20190303231738p:plain

Netlifyにアップロードする

NetlifyとGitHubを連携する

非常に直感的にも連携作業はできますが、公式のドキュメントを見てGitHubと連携します。

https://www.netlify.com/docs/continuous-deployment/

Buildコマンドの設定

Netlifyで設定する際、途中でBuildコマンドを設定するタイミングがあります。 下記の値を設定しましょう。

  • Build Command
    • gridsome build
  • Publish directory
    • dist

https://gridsome.org/docs/deploy-to-netlify

Netlify上で見れるか確認する

サイトをデプロイしたらアクセスして確認しましょう。 無事に表示できていたら完了です。

下記は自分がデプロイしているサイトです。

https://challenge-every-month.netlify.com

まとめ

  • Vue.js製のGridsomeについて簡単に調べて作ってみた。
  • challenge-every-monthのサイト作り頑張る。
  • 2019/03/03でver0.5.4
    • まだまだ開発中!
    • いろいろ貢献できそう!

参考にしました

https://qiita.com/ririli/items/ebd57c3c993e0b8403bd

2019年2月を振り返る

Keep

登壇できた

月に1つLTするという年の目標を設けているので、その継続となります。

今月はLTではありませんでしたが、Laravel JP Conferenceにて、PHPテストワークショップを実施しました。

詳しくはこちら。

yoshitaku-jp.hatenablog.com

イベントの主催ができた

真冬こそ激アツの自由研究LT大会で、運営のリーダーと司会をやりました。リーダーとしては正直名ばかりだった気がしていて、周りの人に本当に助けられてばかりでした。ありがとうございました。 司会としては皆が楽しめる雰囲気を作り出そうとテンションを上げてやりきりました。司会良かったと嬉しいフィードバックもいただけてよかったです。また機会があればやってみたいです。

engineers.connpass.com

サシ飲み企画を実施し、多くの人と話すことができた

2月の目標として後述しますが、非常にいい経験となりましたので無理のない範囲で継続します。

Problem

週1での技術記事を落としてしまった

忙しかったわけではなく、更新したと思ったら忘れていました。 2月4週目分を2月5週目分にプラスし、解消していきます。

自分の時間が取れなかった

周りのイベントごとに気を配りすぎて自分の時間を取ることが難しかったです。 振り返りの時間もまともにできませんでした。

ブログ本文の充実化を図ることができなかった

2月は3000字を超えないと投稿してはいけないルールを引いてみましたが思ったよりも難しかったです。 なおかつ、伝いたい・書きたい本筋から逸脱するような内容を水増しするのはどうなのかと思いました。 このルールは来月には適応しないこととします。

Try

自分の時間の確保

イベントごとに参加する回数を減らします。いろいろお誘いいただくの嬉しいですが、予定詰め込めすぎて手が回らなくなることを避けたいと思います。

2月のチャレンジ企画の結果

2月の目標

週1でサシ飲みをする。

結果:達成(一応)

週一は守れなかったが、5人(5週分)とサシ飲みできた。

  • 普段行かない場所のお店開拓ができた
  • 2人で2時間話すというのはなかなか取れないので楽しかった
  • 別分野の人と呑むことで知らない世界の話が聞けて楽しかった

3月のチャレンジ企画

3月の目標

  1. ロードバイクで遠出する
    • 最近乗れてないので3月の目標にした。
    • 大島一周をやりたい
  2. 積読を解消する。
    • 積み読書が増えてきたので、解消していく。
      • 入門 監視
      • UNIXという考え方―その設計思想と哲学

振り返りおしまい。

Google Apps Scriptを使う上での.clasp.jsonについて調べた

Google Apps Scriptを使用する上で設定しなければいけないのが.clasp.jsonです。自分は.clasp.jsonを正しく設定することを忘れてしまったためにミスをしてしまいました。そこで今回は.clasp.jsonの書き方をまとめておきたいと思います。

.clasp.jsonの設定方法

GitHub上での説明は下記にあります。

https://github.com/google/clasp#project-settings-file-claspjson

.clasp.jsonはプロジェクト設定ファイルとも呼ばれ、clasp cloneclasp createをしたときにカレントディレクトリへ作成されます。 GitHubにあった例を記述しておきます。

{
  "scriptId": "",
  "rootDir": "build/",
  "projectId": "project-id-xxxxxxxxxxxxxxxxxxx",
  "fileExtension": "ts",
  "filePushOrder": ["file1.ts", "file2.ts"]
}

scriptId

Google Scriptプロジェクトを特定するためのIDが記述される場所です。 URLとしてある、https://script.google.com/d/<SCRIPT_ID>/edit<SCRIPT_ID>と同じ値が入ります。

rootDir

どのディレクトリのファイルをプロジェクト上にpushするかを決める項目です。必須項目ではないために指定がない場合は現在のディレクトリをpushします。

rootDirを設定しなかったための失敗

新規で開発をしていたとき、node_modulesと同じディレクトリで開発していました。そして、pushをしてしまった結果は対象のファイルがpushの対象となっており長時間結果が帰ってこない結果となりました。 開発する際ソースコードはsrc配下で開発をし、.clasp.json "rootDir": "src/",とすることをおすすめします。こうすることでプロジェクトにpushされるのはsrc配下だけとなります。

projectId

claspがどのGoogle Cloud PlatformのIDと紐付いているかを特定する項目です。

fileExtension

開発しているソースコードの拡張子を指定します。必須項目ではないため、書かなくても大丈夫なようです。

filePushOrder

ファイルをプッシュする順番を指定します。説明文には、実行順に依存するものがある場合に役立ちますとありますが具体的には思いつきませんでした。すべてがアップロードされてから実行すると思うのですが…。

まとめ

今回はrootDirを正しく設定していないことで問題が発生し、.clasp.jsonを調査することになりました。 しかし、結果として自分が気がついていない機能を発見できてよかったです。 Google Apps Scriptで手軽に開発することが増えてきましたので、今後も調査していきたいと思います。

おしまい。