TablePlusの書き方(sshトンネルで接続したい時)
TablePlusの書き方(sshトンネルで接続したい時)
■ ダウンロードする
TablePlus | Modern, Native Tool for Database Management
■ こちらの記事を参考にsshトンネルで接続してみる
Docker環境のRails7をherokuにデプロイした時にハマった現象まとめ
Docker環境のRails7をherokuにデプロイした時にハマった現象まとめ
1. Heroku Stackの設定
Docker コンテナを Heroku で使用する為にheroku stack:set container
コマンドを叩く必要があります。
このコマンドを叩くことで、Heroku が Dockerfile を使用してアプリケーションのビルドとデプロイを行うよう指示するようになります。
2. heroku.ymlの設定
HerokuでDockerコンテナを使用する場合、heroku.yml
ファイルを作成します。
例)
build: docker: web: Dockerfile run: web: bundle exec puma -C config/puma.rb
3. 環境変数の設定
3.1 DATABASE_URL
Herokuでは、アプリケーションにアタッチされたデータベースアドオンの情報は自動的にDATABASE_URLに保存されます。
Ruby on Railsの場合、database.ymlファイルでデータベースの設定を行いますが、production環境の設定では以下のようにDATABASE_URL環境変数を設定する必要があります。
production: <<: *default database: aaaaa_production username: aaaaa password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %> url: <%= ENV['DATABASE_URL'] %
3.2 PORT
Heroku環境では、アプリケーションがリッスンすべきポート番号が PORT 環境変数によって提供されます。そのため、RailsアプリケーションがHerokuで正しく動作するためには、この PORT 環境変数を適切に使用する必要があります。
例えば、Pumaサーバーを使用している場合、config/puma.rb ファイルで以下のように設定する必要があります。
// ローカル環境など、PORT 環境変数が設定されていない環境でもアプリケーションが動作するようにするため、|| 3000 の部分が必要 port ENV['PORT'] || 3000
3.3 SECRET_KEY_BASE
SECRET_KEY_BASEは、RailsアプリケーションがセッションやCookieを暗号化するために使用する秘密鍵です。
config/credentials.yml.enc ファイルにある secret_key_base の設定を確認し、herokuの'production'環境用のシークレットキーを追加する必要があります。
4. ローカルでassets:precompileしてからデプロイする
herokuにCSSが反映しないので、 ローカルでassets:precompileしてからデプロイした。
ただし、この記事をみる限り、Herokuではデプロイ時に自動的にassets:precompileが実行されるようになっているのでこの作業が必要かどうかは怪しい。
Docker環境でGemfileを変更してもインストールされない
発生手順
- gemfileにgem追加
- docker-compose run --rm web bundle install
- dockerコマンド叩く(例: docker-compose run --rm web bundle exec rubocop)
➜ git:(master) ✗ docker-compose run --rm web bundle exec rubocop Creating compass-backend_web_run ... done ERROR: ld.so: object '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored. bundler: command not found: rubocop Install missing gem executables with `bundle install`
bundle installできてないとエラーになる
原因
Dockerのイメージの再ビルドをしていない。 Gemfileを変更したときは、イメージの再ビルドを行わないと、gemはインストールされない
解決
- docker-compose down -v
- docker-compose build --no-cache
- docker-compose up
1で既存のvolume削除して、2で再度コンテナ立ち上げる
参考記事
Vue3を開発する時のVsCodeのおすすめプラグイン設定
Vue3を開発する時のVsCodeのおすすめプラグイン設定
おすすめ拡張機能紹介
1. Volar
Volar は Vue.js の開発をサポートする VS Code の拡張機能です。.vue ファイルのシンタックスハイライトやインテリセンスによる補完ができるようになります。詳細は、Volar の GitHub リポジトリ (opens new window)を参照してください。
GitHub - johnsoncodehk/volar: ⚡ Explore high-performance tooling for Vue
2. Vue3 snippest
スニペットを使用する機能を提供してくれます
Vue 3 Snippets - Visual Studio Marketplace
3. Vue Peek
選択したコンポーネントがどこで定義しているか表示してくれる
Vue.jsを使う人が最低限導入しておきたいVisual Studio Codeの拡張機能 – Webrandum
4. Prettier
バラバラに書かれたコードを、自動的に綺麗にしてくれます。
【自動整形】VSCodeでPrettierを使う方法【設定必要です】 | RalaCode
5.Auto Rename Tag
開始タグを修正すると自動で閉じタグも修正してくれる拡張機能「
Visual Studio Codeで開始タグを修正すると自動で閉じタグも修正してくれる拡張機能「Auto Rename Tag」 – Webrandum
7. JavaScript (ES6) code snippets
JavaScript (ES6) code snippets - Visual Studio Marketplace
8. Material Icon Theme
Material Icon Themeを設定するとフォルダにもアイコンが表示されるようになります。
マネタイズ方法まとめ
マネタイズ方法まとめ
WEBサービスでマネタイズするパターンをそれぞれ記載します
1. 機能絞り込み
機能を絞り込み、人気機能を利用するには有料プランに以降を促す
例) - Pairs - openwork
■ メリット
- ユーザーが気軽にサービス利用できる
■ デメリット
- 魅力的な有料プランでなければ課金されない
2.フリーミアムモデル
最初無料でインストールできるが、特定のところまで行くと課金が必須になる(初月無料的な)
■ メリット
- ユーザーが気軽にお試し利用できる
■ デメリット
- 無料期間に魅力を感じなければ課金されない
3. 広告表示
広告を表示させて、その表示回数に合わせて広告料金をもらう
■ メリット
- 導入が容易
■ デメリット
4.サブスクリションモデル
月額制で利用料金を支払うサブスクリションモデル
例) - netflex
■ メリット
- ストックビジネスにつながる
■ デメリット
- サブスクビジネスモデルの競合が多い(ライバルが多い)
5.手数料サービス
プラットフォームサービスでユーザーと企業がマッチングした時に発生する金額の一部を成果報酬として得る。
例) - Menta
■ メリット
- toBであれば取引金額が高い
■ デメリット
- ユーザー同士の揉め事があった時の対応がしんどい
Nuxt3でvalidationする方法
Nuxt3でvalidationする方法
インストール
npm i vee-validate @vee-validate/i18n @vee-validate/rules
vee-validate -> veeValidate
@vee-validate/i18n -> バリデーションエラーメッセージに日本語化
@vee-validate/rules -> バリデーションルールを利用する
pluginの設定
■ plugins/vee-validate.client.ts
import { localize, setLocale } from "@vee-validate/i18n"; // VeeValidateで用意されている英語語版入力チェックエラーメッセージを使う import en from "@vee-validate/i18n/dist/locale/en.json"; // VeeValidateで用意されている日本語版入力チェックエラーメッセージを使う import ja from "@vee-validate/i18n/dist/locale/ja.json"; import AllRules from "@vee-validate/rules"; import { defineRule, configure } from "vee-validate"; import { defineNuxtPlugin } from "#app"; export default defineNuxtPlugin((_nuxtApp) => { configure({ generateMessage: localize({ en, ja }), }); configure({ generateMessage: localize('ja', { names: { password: 'パスワード', email: 'Email' }, }), }); Object.keys(AllRules).forEach((rule) => { defineRule(rule, AllRules[rule]); // 全ルールを使えるようにする }); setLocale("ja"); });
Fieldのバリデーション
<template> <div class="min-h-screen flex flex-col"> <div class="container max-w-md mx-auto flex-1 flex flex-col items-center justify-center px-2" > <div class="bg-white px-6 py-8 text-black w-full"> <h1 class="mb-8 text-3xl text-center"> 新規登録 🎉 </h1> <input v-model="email" type="text" class="block border border-grey-light w-full p-3 rounded mb-4" name="email" placeholder="Email" > <input v-model="password" type="password" class="block border border-grey-light w-full p-3 rounded mb-4" name="password" placeholder="Password" > <input v-model="passwordConfirm" type="password" class="block border border-grey-light w-full p-3 rounded mb-4" name="passwordConfirm" placeholder="Confirm Password" > <button type="submit" :class="validInput ? 'bg-indigo-500 hover:bg-indigo-700' : 'bg-gray-500'" class="block border border-grey-light w-full p-3 rounded mb-4 text-white" :disabled="!validInput" @click="register" > 登録 </button> </div> </div> </div> </template> <script> import { useField } from 'vee-validate'; export default { setup() { const { value: email, errorMessage: emailError } = useField( "email", "required|email", ); const { value: password, errorMessage: passwordError } = useField( "password", "required|min:5", ); const { value: passwordConfirm, errorMessage: passwordConfirmError } = useField('passwordConfirm', (passwordConfirm) => { if ( passwordConfirm === password.value) { return true; } return 'パスワードと一致してません'; }); return { email, emailError, password, passwordError, passwordConfirm, passwordConfirmError } }, } </script>
参考リンク
Nuxt3とfirebase9で認証機能設定する方法
Nuxt3とfirebase9で認証機能設定する方法
各バージョン
Nuxt: 3.0.0-rc.11
Firebase: 9.13.0
インストール
npm install firebase
でpackage.json
にfirebase
が追加されればOK
Firebaseの初期設定
■ plugins/firebase.client.ts
import { initializeApp } from 'firebase/app' import { defineNuxtPlugin } from '#app' export default defineNuxtPlugin(() => { const config = useRuntimeConfig() const firebaseConfig = { apiKey: config.FIREBASE_API_KEY, authDomain: config.FIREBASE_AUTH_DOMAIN, projectId: config.FIREBASE_PROJECT_ID, storage_bucket: config.FIREBASE_STORAGE_BUCKET, messaging_sender_id: config.FIREBASE_MESSAGING_SENDER_ID, api_id: config.FIREBASE_API_ID, measurement_id: config.FIREBASE_MEASUREMENT_ID, } initializeApp(firebaseConfig) })
(Authenticationのみで利用するので、初期化時の引数はapiKeyとauthDomainとprojectIdの3つを最低限指定しておけば問題なく動く。)
- plugins ディレクトリについて
- pluginsディレクトリ配下のjsファイルは自動的に読まれるので、nuxt.config.jsへの設定は不要。
- defineNuxtPluginというplugin読み込み用の関数が用意されているので、これを使う。
- プラグイン内でランタイムの設定を使用したい場合は、defineNuxtPlugin 関数内でuseRuntimeConfig() を使用する
Nuxt3はdotenvが内包されているので.envでお手軽に環境変数を設定する
■ .env
FIREBASE_API_KEY=**************** FIREBASE_AUTH_DOMAIN=**************** FIREBASE_PROJECT_ID=**************** FIREBASE_STORAGE_BUCKET=**************** FIREBASE_MESSAGING_SENDER_ID=**************** FIREBASE_API_ID=**************** FIREBASE_MEASUREMENT_ID=G-****************
nuxt3には、実行時に設定値をロードするための仕組みとしてruntimeConfigというものがある。コンポーネント内からはuseRuntimeConfigや$configで値にアクセスすることができる。
■ nuxt.config.ts
runtimeConfig: { public: { FIREBASE_API_KEY: process.env.FIREBASE_API_KEY || '', FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN || '', FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID || '', FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET || '', FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID || '', FIREBASE_API_ID: process.env.FIREBASE_API_ID || '', FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID || '', }, },
例)config.FIREBASE_API_KEY
と記載すれば.envで設定されたFIREBASE_API_KEYの値が取得できる
各認証メソッド
認証の処理はcomposableにまとめる。
Composables directoryではこちらのドキュメントの通り、各Componentでimportを書かなくても呼び出しができるものになります。
■ composables/useAuth.ts
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut as firebaseSignOut, onAuthStateChanged, GoogleAuthProvider, signInWithPopup, TwitterAuthProvider } from 'firebase/auth' export const useAuth = () => { const token = useState<string>('token', () => null) // メールアドレス新規登録関数 async function signUp(email:string, password:string){ return await new Promise((resolve)=>{ // getAuth()でAuthを取得 const auth = getAuth() // メールアドレスとパスワードでアカウントを作成する createUserWithEmailAndPassword(auth, email, password) .then((userCredential) => { console.log(userCredential) // サインアップできたらログインする resolve("success") }) .catch((error) => { console.log(error) const errorMessage = error.message; resolve(errorMessage) }) }) } // メールアドレスとパスワードでログインする関数 async function signIn(email: string, password: string) { return await new Promise<void>((resolve, reject) => { const auth = getAuth() // メールアドレスとパスワードでログインする return signInWithEmailAndPassword(auth, email, password) .then((userCredential) => { userCredential.user .getIdToken() .then((idToken) => { token.value = idToken resolve() }) .catch(reject) }) .catch(reject) }) } // ログアウトする関数 async function signOut() { return await new Promise<void>((resolve, reject) => { const auth = getAuth() // ログアウトする firebaseSignOut(auth) .then(() => { token.value = null resolve() }) .catch((error) => { reject(error) }) }) } // ログイン状態確認関数 async function checkAuthState() { return await new Promise<void>((resolve, reject) => { // client only if (process.server) return resolve() const auth = getAuth() onAuthStateChanged( auth, (user) => { if (user) { user .getIdToken() .then((idtoken) => { token.value = idtoken resolve() }) .catch(reject) } else { token.value = null resolve() } }, (error) => { reject(error) } ) }) } // google認証関数 async function loginWithGoogle() { const auth = getAuth(); const provider = new GoogleAuthProvider(); signInWithPopup(auth, provider) .then((result) => { const credential = GoogleAuthProvider.credentialFromResult(result); const token = credential?.accessToken; const user = result.user; console.log({ credential, token, user }); }) .catch((error) => { const errorCode = error.code; const errorMessage = error.message; const email = error.email; const credential = GoogleAuthProvider.credentialFromError(error); console.log({ errorCode, errorMessage, email, credential }); }); }; // twitter認証関数 async function loginWithTwitter() { const auth = getAuth(); const provider = new TwitterAuthProvider(); signInWithPopup(auth, provider) .then((result) => { const credential = TwitterAuthProvider.credentialFromResult(result); const token = credential?.accessToken; const user = result.user; console.log({ credential, token, user }); }) .catch((error) => { const errorCode = error.code; const errorMessage = error.message; const email = error.email; const credential = TwitterAuthProvider.credentialFromError(error); console.log({ errorCode, errorMessage, email, credential }); }); }; return { signUp, signIn, signOut, token, checkAuthState, loginWithGoogle, loginWithTwitter } }
ログイン状態の永続性
■ middleware/auth.ts
export default defineNuxtRouteMiddleware(async () => { if (!process.server) { const { checkAuthState, token } = useAuth() await checkAuthState() if (!token.value) { return navigateTo('/login', { replace: true }) } } })
Page コンポーネントや Layout コンポーネントにて、使用する middleware を指定すると、コンポーネントが作成 (setup) される前に(ページ遷移に先立ち) middleware 内の指定のファイルが実行されます。
<script setup> definePageMeta({ middleware: ['auth'] }) </script>
参考
Nuxt3 & Firebase9でFirebase Authentication決定版
Nuxt3のruntimeConfigで環境変数を設定する | デバッグライフ