- 投稿日:2019-02-28T22:47:02+09:00
LaravelのElopuentでリレーション関係の子データを取得して、そのデータをVue.jsで使用するときに困った
はじめての記事なのでうまく伝わるかわかりませんが、
joinを使わないやり方で調べてもなかなか出てこなかったので備忘録。DBの構成
Employee(社員)テーブル
+---------+--------+---------------+ | id | name | department_id | +---------+--------+---------------+ | 1 | 田中 | 1 | | 2 | 鈴木 | 2 | | 3 | 佐藤 | 3 | | 4 | 吉田 | 1 | +---------+--------+---------------+Department(部署)テーブル
Department(部署)テーブル +---------+-----------+ | id | name | +---------+-----------+ | 1 | 営業部 | | 2 | 経理部 | | 3 | 技術部 | +---------+-----------+このとき、EmployeeテーブルとDepartmentテーブルのリレーションは多対1になります。
リレーションの簡単な説明(前置き)
このテーブルを使って、社員の一覧を表示する。
その際に、社員それぞれの部署名も一緒に表示させたい。こういう風な一覧を作りたい
+---------+--------+------------+ | id | name | department | +---------+--------+------------+ | 1 | 田中 | 営業部 | | 2 | 鈴木 | 経理部 | | 3 | 佐藤 | 技術部 | | 4 | 吉田 | 営業部 | +---------+--------+------------+Laravelでは、リレーションを張ることで、簡単に表示させることができるようです。
リレーションに関するドキュメント
https://readouble.com/laravel/5.7/ja/eloquent-relationships.htmlそれぞれのModelクラスを作り、Employee.phpを以下のように記述
Employee.php<?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { /** * この社員が持っているdepartment_idと一致するレコードを部署テーブルから取得 */ public function department() { return $this->belongsTo('App\Department'); } }belongsTo関数を第1引数しか使わない場合は、関数名はテーブル名にしないといけないようです。
関数名_id と belongsTo() の第1引数で指定したモデルが持つidを結びつけるとのこと。idとして使うカラムの名前が違う場合は、第2、第3引数で変更できるみたいです。
そして、あとは社員テーブルの一覧を普通に取得するだけ
Employee.phppublic function get() { $results = Employee::all(); return $results; }これだけで勝手にDepartmentテーブルのデータと結合してくれます。
phpで使うなら$result->department->nameで部署名が取れます。
真ん中のdepartmentはテーブルじゃなく関数名っぽいです。
1対1だったり、この例題と逆の参照でやる場合とかはドキュメントに乗ってたり
他の人が書いてくれているのでそちらを参考にここからが本題
本題
これをAPIを使ってVue.jsで受け取ったあと
Vue.js{{ result.department.name }}こんな感じで表示させようとしたときにエラーがでました。
Error in render: "TypeError: Cannot read property 'name' of undefined"console.logとかで見てもあるやん!としかならなくて困りました。
多分、レスポンスを返すときにresponse()->json()でjsonにしていたつもりが
departmentの中までは正しく変換されていなかった感じだと思います。
(よくわかんないので詳しい方解説してくれれば嬉しいです...)そういう雰囲気で検索かけたら、stackoverflowに質問していた方がいて、
さらに回答してくれている方がいました!解決策
https://stackoverflow.com/questions/37289274/convert-eloquent-relationship-into-vue-js-code
社員一覧を取得するときに、こう書けよということみたいです
Employee.phppublic function get() { // $results = Employee::all(); $results = Employee::with('department')->all(); return $results; }withの中はbelongsToを使っている関数名っぽいです
Modelクラスのつもりなんでそのままリターンしてますが、
クライアントに返すときはちゃんとJsonにして返すといいと思います。指摘があれば教えて下さい。
同じ境遇の人の助けになると嬉しいですm(_ _)m
- 投稿日:2019-02-28T22:47:02+09:00
LaravelのEloquentでリレーション関係の子データを取得して、そのデータをVue.jsで使用するときに困った
はじめての記事なのでうまく伝わるかわかりませんが、
joinを使わないやり方で調べてもなかなか出てこなかったので備忘録。DBの構成
Employee(社員)テーブル
+---------+--------+---------------+ | id | name | department_id | +---------+--------+---------------+ | 1 | 田中 | 1 | | 2 | 鈴木 | 2 | | 3 | 佐藤 | 3 | | 4 | 吉田 | 1 | +---------+--------+---------------+Department(部署)テーブル
Department(部署)テーブル +---------+-----------+ | id | name | +---------+-----------+ | 1 | 営業部 | | 2 | 経理部 | | 3 | 技術部 | +---------+-----------+このとき、EmployeeテーブルとDepartmentテーブルのリレーションは多対1になります。
リレーションの簡単な説明(前置き)
このテーブルを使って、社員の一覧を表示する。
その際に、社員それぞれの部署名も一緒に表示させたい。こういう風な一覧を作りたい
+---------+--------+------------+ | id | name | department | +---------+--------+------------+ | 1 | 田中 | 営業部 | | 2 | 鈴木 | 経理部 | | 3 | 佐藤 | 技術部 | | 4 | 吉田 | 営業部 | +---------+--------+------------+Laravelでは、リレーションを張ることで、簡単に表示させることができるようです。
リレーションに関するドキュメント
https://readouble.com/laravel/5.7/ja/eloquent-relationships.htmlそれぞれのModelクラスを作り、Employee.phpを以下のように記述
Employee.php<?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { /** * この社員が持っているdepartment_idと一致するレコードを部署テーブルから取得 */ public function department() { return $this->belongsTo('App\Department'); } }belongsTo関数を第1引数しか使わない場合は、関数名はテーブル名にしないといけないようです。
関数名_id と belongsTo() の第1引数で指定したモデルが持つidを結びつけるとのこと。idとして使うカラムの名前が違う場合は、第2、第3引数で変更できるみたいです。
そして、あとは社員テーブルの一覧を普通に取得するだけ
Employee.phppublic function get() { $results = Employee::all(); return $results; }これだけで勝手にDepartmentテーブルのデータと結合してくれます。
phpで使うなら$result->department->nameで部署名が取れます。
真ん中のdepartmentはテーブルじゃなく関数名っぽいです。
1対1だったり、この例題と逆の参照でやる場合とかはドキュメントに乗ってたり
他の人が書いてくれているのでそちらを参考にここからが本題
本題
これをAPIを使ってVue.jsで受け取ったあと
Vue.js{{ result.department.name }}こんな感じで表示させようとしたときにエラーがでました。
Error in render: "TypeError: Cannot read property 'name' of undefined"console.logとかで見てもあるやん!としかならなくて困りました。
多分、レスポンスを返すときにresponse()->json()でjsonにしていたつもりが
departmentの中までは正しく変換されていなかった感じだと思います。
(よくわかんないので詳しい方解説してくれれば嬉しいです...)そういう雰囲気で検索かけたら、stackoverflowに質問していた方がいて、
さらに回答してくれている方がいました!解決策
https://stackoverflow.com/questions/37289274/convert-eloquent-relationship-into-vue-js-code
社員一覧を取得するときに、こう書けよということみたいです
Employee.phppublic function get() { // $results = Employee::all(); $results = Employee::with('department')->all(); return $results; }withの中はbelongsToを使っている関数名っぽいです
Modelクラスのつもりなんでそのままリターンしてますが、
クライアントに返すときはちゃんとJsonにして返すといいと思います。指摘があれば教えて下さい。
同じ境遇の人の助けになると嬉しいですm(_ _)m
- 投稿日:2019-02-28T22:19:01+09:00
Firebase+Nuxt.jsでともだちのSNSリンクを一カ所で管理できるサービスを作ってしまった......【個人開発】
じぇいです!
今回僕は、Firebaseの勉強にサービスを一つリリースしました。
それは!
ともだちのSNSリンクを一カ所で管理できる「ともだちびお」というサービスです。
Firebase+Nuxt.jsで作りました!Firebaseは初めての挑戦です。
リリースツイートはこちらです!え、リツイートしてくれますよね...?
?友人などのSNSリンクを一箇所管理できる「ともだちびお」をリリースしました!㊗️㊗️㊗️
— じぇい?? (@jyouj__) February 28, 2019
Firebase×Nuxt.jsでつくりました!Firebaseをはじめて使ったんですが、便利で感動しました!
ぜひ触ってみてください!https://t.co/msQC3Z9F2wサービス内容
サービス内容はともだちのSNSリンクを一カ所で管理できる連絡帳サービスです。
Twitter, Facebook, Instagram, Githubなどのリンクを登録できます!
使ったもの
Nuxt.js
Vue.jsをさらに便利に活用できるフレームワーク。SPAもSSRもどっちも来い!っていうなんでもできちゃう感。SPAで今回は作りました!
Firebase Authentication
Twitter認証に使いました(後述)。
Firebase Realtime Database
基本的なCRUDを実装しました(後述)。ルール定義で自分の保存データしかアクセスできないようにすることで連絡帳サービスを実装しています。Firestoreも興味深かったのですが、学習コストがたかそうだったので、まずはRealtime Databaseからにしました。
Firebase Hosting
デプロイもものすごく簡単!カスタムドメインにもSSL接続を無料でできてハッピー!
FontAwesome
最初、CDNで使ってたんですが速度が遅かったので最終的にはnpmパッケージで使うことにしました。使うアイコンだけ
library.add()
すれば、読み込みも遅くなりません。nuxt-buefy
BulmaのVueに最適化したフレームワーク。細かい部品は頼りきりでした。
vue-lazyload
画像の遅延読み込みに使いました。少しは速度は改善したはず......。
vue-burger-menu
おしゃれなバーガーメニューを実装できます。
vue-tags-input
タグの入力に使いました。
@nuxtjs/pwa
PWA対応を簡単にできます。ただTwitter OAuthを使っているので一度Safariに遷移してしまってあまりうまく使えてません。Androidはできてるのかな?
@nuxtjs/google-analytics
Google Analyticsの設定が楽々!
Firebaseの認証・CRUD
認証
Twitterログイン
methods: twitterLogin () { var provider = new firebase.auth.TwitterAuthProvider() firebase.auth().signInWithPopup(provider) } }ログアウト
logout: function() { firebase.auth().signOut(); },ログインしてるかのチェック
firebase.auth().onAuthStateChanged(user => { if (user) { this.isLogin = true this.user = user } else { this.isLogin = false this.user = null }; })CRUD
Create(投稿)
var newLinkKey = firebase.database().ref().child('posts').push().key; firebase .database() .ref('posts/' + this.user.uid + '/' + newLinkKey) .set({ content: this.content, // 省略 })Read(読み取り)
firebase.database().ref('posts/' + this.user.uid).on('value', function(snapshot) { this.posts = snapshot.val() })Update(更新)
var newPost = { content: this.content // 省略 } var updates = {} updates['/posts/' + this.user.uid + '/' + key] = newPost firebase.database().ref().update(updates)Delete(削除)
firebase.database().ref('links/' + this.user.uid + '/' + key).remove();最後に
Firebaseはこれだけでマイクロサービスを作り上げることができます。
Nuxt.jsと組み合わせることでサービスの幅も広がって良き良き。
Twitterフォローしてねー!
- 投稿日:2019-02-28T21:13:56+09:00
Vue.jsでグラデーションのアニメーション表示をしよう!Granim.js
Granim.js
Granim.jsはグラデーションをアニメーション表示させることができるJavaScriptライブラリです。
これを使うと、リッチなWebサイトを作ることができます!どのようにアニメーション表示されるかは公式サイトのトップページやExamplesをご覧ください。
このGranim.jsをVue.jsのアプリケーションで使ってみます。
手順
1.Gramin.jsのインストール
npm install granim2.コンポーネントの作成
granim.vue<template> <div> <canvas id="granim-canvas"></canvas> </div> </template> <script> import Granim from 'granim' export default { name: 'granim', data () { return { GObj: Object } }, mounted () { this.GObj = new Granim({ element: '#granim-canvas', name: 'granim', opacity: [1, 1], states: { 'default-state': { gradients: [ ['#29323c', '#485563'], ['#FF6B6B', '#556270'], ['#80d3fe', '#7ea0c4'], ['#f0ab51', '#eceba3'] ] } } }) } } </script> <style scoped> #granim-canvas { width: 100vw; height: 100vh; } </style>キモはコンポーネントのmountedライフサイクルフックでGranimをnewするところです。
mounted()に記述するコードは公式サイトの通りに記述すればOKです。
newするときのオプションでスピードや色の指定など様々な表現ができます。※上のサンプルコードではESLintのエラー回避のためにdataにnewしたGranimのインスタンスを代入しています。
3.完成!
バリエーション
Granim.jsを使うとただのグラデーションだけではなく、画像と組み合わせたり、文字に対してグラデーションのアニメーションをつけることができます。公式サイトにやり方が載っています。
- 投稿日:2019-02-28T17:18:50+09:00
Vueで画像を遅延読み込みするライブラリ v-lazy-image
先日書いた表示速度改善の続きで、画像の遅延読み込みをするために、ライブラリを探してみたところ、v-lazy-imageが良い感じだったので紹介。
導入
$ npm install v-lazy-image --save使い方
App.vueとかでプラグインとして読み込む場合
import Vue from "vue"; import { VLazyImagePlugin } from "v-lazy-image"; Vue.use(VLazyImagePlugin);必要な箇所で個別に使う場合
import VLazyImage from "v-lazy-image"; export default { components: { VLazyImage } };あとは公式にある通り、
v-lazy-image
タグを使ってやれば良い。<template> <v-lazy-image src="http://lorempixel.com/400/200/" /> </template>もちろん、propsやdataの値を渡すこともできる。
<template> <v-lazy-image :src="imageURL" /> </template> <script> import VLazyImage from "v-lazy-image"; export default { components: { VLazyImage }, props: { imageURL: { type: String, default: null } } } </script>あとは、出力されるimgタグに
v-lazy-image
とv-lazy-image-loaded
のclassが付与されるので、こんな感じでアニメーションをつけることができる。<style scoped> .v-lazy-image { filter: blur(10px); transition: filter 0.7s; } .v-lazy-image-loaded { filter: blur(0); } </style>最初はvue-lazyloadを使おうかと思ってたけど、画像の遅延読み込みのためだけならv-lazy-imageの方が軽くて良い感じ。
- 投稿日:2019-02-28T12:24:51+09:00
laravel-mix + Vue.js (ES) + WebWorker (TS)
追記
2019-02-28 12:33
よさそう。
GoogleChromeLabs/comlink: Comlink makes WebWorkers enjoyable.
参考: WebWorkerをenjoyableにするComlinkとは何者か - Qiita
概要
laravel-mix + Vue.js (ES2018+) + ロジック部分は TypeScript というプロジェクトに、ちょっと Web Worker を導入したくなったのでやったというものです。
この記事は「こうやったら出来た」というメモでありベストプラクティスではないので、 Web Worker 初歩の参考の1つ程度にしていただければと思います。Worker とは
Worker です。非同期処理による似非マルチスレッドではなく、真のマルチスレッドをもたらします。恐らく。
詳細や正確なところはは色んな方が解説されているかと思うのでぐぐってください!Web Workers API - Web API | MDN
本記事では専用 Worker についてのみ言及します。
Worker の使い方
メインの JS とは別に Worker 用のコードを用意します。
インラインで文字列として記述したり別の<script>
タグ中に記述したりでも大丈夫なそうですが、ここでは別ファイルとして用意します。大まかに以下のような感じで使います。
main.jsimport Worker from './path/to/file.worker.js' const worker = new Worker() // `new Worker('./path/to/file.worker.js')` とかでも出来るそうな…。 // 個人的にはコード中で参照されるファイルパスは // `import ~ from ~` のように一箇所にまとめたい気持ちがあります。 worker.addEventListener('message', e => { const { data } = e console.log( data ) // => 500 // worker を終了させる場合は実行。 worker.terminate() // もしくは worker 側から `self.close()` を実行するとその場で worker が終了します。 }) // worker に `100` を送信。 worker.postMessage(100)path/to/file.worker.jsaddEventListener('message', e => { // `data` にはメインから渡された `100` が入ってくる。 const { data } = e // `5` を掛けてメインスレッドに送信。 postMessage( data * 5 ) })今回やったこと
laravel-mix
をコンパイラとして使っているプロダクトで、 Vue.js 製アプリケーション内から TypeScript 製 WebWorker を利用するということを行いました。
laravel-mix
の設定
.webpackConfig()
で Webpack の設定を行うだけです。ローダーは
worker-loader
を以下のように設定しました。
Worker のファイル自体は TypeScript で書いていくので、ts-loader
も一緒に指定しています。{ module: { rules: [ { test: /\.worker\.ts$/, use: [ { loader: 'worker-loader', options: { name: '[name].js' } }, 'ts-loader' ] }, { test: /\.ts$/, // Worker は Worker としてファイルを分離したいので除外設定 (そうしないとバンドルされちゃうかなぁと思って…) exclude: /\.worker\.ts$/, loader: 'ts-loader' } ] } }上記の設定に落ち着くまで以下のような挙動をされて躓きました。
worker-loader
でname
を指定しないと出力ファイル名がハッシュ値になり、ビルドの度に違う Worker ファイルが生まれる。worker-loader
でpublicPath
を指定するとそのディレクトリに出力されるが、 Vue.js アプリケーション内からの Worker 参照パスがおかしい。(存在しないパスを参照して 404 になる)これらの理由から
name
を固定し、publicPath
を設定していません。
ただこれだと Worker ファイルの出力先がlaravel-mix
デフォルトの./public
直下になってしまうので、ちょっと嫌だなぁとなっているところです。ちょっとどうにかしたい…。
tsconfig.json
の設定
compilerOptions.lib
に"webworker"
を追加します。
VSCode でも IntelliSense が効いてくれるようになります。Worker を書く
TSで書きます。
path/to/file.worker.tsinterface IMessageEvent extends MessageEvent { data: number } addEventListener('message', (e: IMessageEvent) => { postMessage( e.data * 5 ) })最低限これだけです。
最終的に Webpack で1つのファイルにまとめるので、 Worker 内でもimport
やrequire()
が使えます。Vue.js コンポーネント内から Worker を利用する
利用します。
path/to/vue/component.vueimport Worker from 'path/to/file.worker.ts' export default { // ... data(){ return { num: 1 } }, methods: { handleWorker(){ const worker = new Worker() worker.onmessage = e => { this.$data.num = e.data worker.terminate() } worker.postMessage( this.$data.num ) } } }
handleWorker()
を実行する度に Worker を経由して$data.num
の数値が5倍されていきます。
MDNの こことか にも結構複雑なコードがあったりするので、 Worker をラップした何かを使ってコントロールするのがいいんでしょうか。
素のまま Worker を使っていくのはなんだか苦しく感じました。
- 投稿日:2019-02-28T09:05:56+09:00
8年前に作った HTML5 アプリを最近の技術で作り直した話(5年ぶり2回目)
icotile は、HTML5 を活用して iTunes のような操作感で Twitter の友達やリストを管理できる Web アプリケーションです。2011年に最初のバージョンをリリースし、2014年には、AngularJS と Bootstrap で全面的に書き換えた icotile2 をリリースしました。この8年間で延べ 55,000ユーザーに利用されている Web アプリです。
随分ほったらかしにしていたのですが、いまだに意外と使われていて、たまに要望とかもいただいていました。最近プロダクトを作っていなかったので、最新の技術を勉強するために、icotile3 の開発に着手しました。
随分古い技術スタックだったのと、勉強も兼ねているので、できるだけまだ使ったことのない技術を採用してみました。また、サーバサイドの Node.js への置き換えも行って、フロントエンドとバックエンドの共通化も図ってみました。機能はほぼ同等+アルファですが、データベース以外はほぼ置き換えです。
icotile (2011) icotile2 (2014) icotile3 (2019) Framework jQuery AngularJS 1.x Vue.js / Vuex UI jQuery UI Bootstrap Vuetify Style スキューモーフィック風 フラットデザイン マテリアルデザイン Lang JavaScript JavaScript TypeScript Backend PHP / CakePHP PHP / CakePHP NodeJS / Express DB MySQL MySQL MySQL Server Apache Apache Apache + nginx Protocol HTTP HTTP HTTPS その他 - - docker / docker-compose での環境構築、PM2 でのプロセス管理等。 関連記事 Twitter の友達やリストを iTunes 風に管理できるアプリ「icotile」(アイコタイル)をリリース 3年ぶりのバージョンアップ!AngularJS などの最新技術で再構築した Twitter リスト管理アプリ「icotile2」リリース! Vue.js/Vuex/Vuetify
Angular は複雑で理解するのに時間がかかったのですが、Vue.js/Vuex は構造がシンプルで、ドキュメントもわかりやすく、どんどん理解できてどんどんコードが書ける感じが気持ちよかったです。
React/Redux は仕事で散々やったので、今回 Vue をトライしてみました。React は、Redux とのつなぎこみが面倒だったので、その辺りは Vuex の方がうまく統合されていてわかりやすかったです。
あと、どちらかというと、UI フレームワークの Vuetify がとても良くできていて、素早く UI 開発ができました。前回は、Angular
と Bootstrap を自分で統合していたのですが、それが一切なく、すぐにマテリアルデザインのアプリが出来上がるのがよかったです。また、今回初のモバイル対応も簡単にできました。TypeScript
TypeScript は部分的に使った感じでしたが、定義したデータ型をフロントエンドとバックエンドで共有して、コンパイル時にエラーをチェックできたのはよかったです。それ以外は結構
any
で逃げた感じ。Node.js/Express
さすがにもう PHP は覚えていないので、Node.js/Express に置き換え。フロントエンドとバックエンドで同じ言語で開発できるのはやっぱり楽ですね。プロセスの管理は PM2 を使用しました。
nginx
フロントエンドと API をルーティングするために、nginx を使ってみました。フロントは、普通に Web サーバとして、ビルドされたスタティックをサーブし、API は Express のローカルサーバへのプロキシとして動かしてます。これが正しいのかは良くわからず...
Docker
一番大変だったのは、Docker での環境構築で、概念を習得するのも、試行錯誤するのも時間がかかりました。いまだに正しい使い方をしているか自信ないですが、ステージングと本番環境をすぐに立ち上げられたり、ローカルで同じ環境で試せるのはよかったです。
あと、PM2 の設定や Bitbucket からの Webhook での更新とか、いろいろトライして、いろいろ勉強になりました。
今後
今回モバイル対応もしたので、Android 向けに PWA でアプリ化したいのと、iOS でネイティブクライアントを作ろうと思っています。MVVM や RxSwift の勉強のために。
と、特にオチもないですが、機能的にも色々進化しているので、Twitter をやってましたら、ぜひ icotile3 をお試しください。