ts-nodeで始めるTypeScript
ついにTypeScriptに手を出す時が来た
ローカルマシンでの実行環境はts-nodeが代表的らしい
バージョン 🔗
$ node -v
v14.4.0
$ npm -v
6.14.8
ts-nodeのインストール 🔗
$ npm install -g typescript ts-node
$ ts-node -v
v9.0.0
対話形式で実行 🔗
$ ts-node
> const n: number = 123;
undefined
> const s: string = '456';
undefined
> n + s
'123456'
> n * 2
246
> s / 3
[eval].ts:5:1 - error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
5 s / 3
~
undefined
ファイルから実行 🔗
const greeter = (username: string) => `Hello, ${username}!`
const username: string = 'Takagi';
console.log(greeter(username));
$ ts-node app.ts
Hello, Takagi!
おわり 🔗
これでカタカタおじさんの仲間入り
【Ruby】バージョン番号のソート
問題 🔗
文字列で表されたバージョンをソートすると正しくない結果になる
“2"と"10"では"2"の方が大きい値と判断される(“10"の"1"の部分を先に評価してしまうため)
['1.1.1', '1.2.10', '1.10.1', '1.2.2'].sort
=> ["1.1.1", "1.10.1", "1.2.10", "1.2.2"]
解決方法 🔗
文字列で表現されたバージョンを比較可能にするためのクラス(Gem::Version)を使えば解決する
(本来、Gemのバージョンを取り扱うために用意されたクラスだけど)
['1.1.1', '1.2.10', '1.10.1', '1.2.2'].sort_by{ |version| Gem::Version.new(version) }
=> ["1.1.1", "1.2.2", "1.2.10", "1.10.1"]
参考 🔗
Ruby 3.0.0 Preview 1を試す
Ruby 3.0.0 Preview 1がリリースされたっぽいので一応触ってみた
Ruby 3.0.0 Preview 1 Released https://t.co/o6lkjD5PKw
— Ruby Programming Language (@rubylangorg) September 25, 2020
Ruby 3.0.0 Preview 1を手に入れる 🔗
$ docker pull rubylang/ruby:3.0.0-preview1-bionic
3.0.0-preview1-bionic: Pulling from rubylang/ruby
f08d8e2a3ba1: Pull complete
3baa9cb2483b: Pull complete
94e5ff4c0b15: Pull complete
1860925334f9: Pull complete
434ea235d88d: Pull complete
f570e67a5e0c: Pull complete
ae0609335980: Pull complete
8d17f446c58f: Pull complete
14b29e11e63e: Pull complete
8bc4734d3ba1: Pull complete
Digest: sha256:04a9656eb5a0ffb41017de92a78963286819a984e39d842e67387bf1a417dd17
Status: Downloaded newer image for rubylang/ruby:3.0.0-preview1-bionic
docker.io/rubylang/ruby:3.0.0-preview1-bionic
$ docker run --rm -it rubylang/ruby:3.0.0-preview1-bionic ruby -v
ruby 3.0.0preview1 (2020-09-25 master 0096d2b895) [x86_64-linux]
追加された機能(ほんの一部)を試す 🔗
これでirbを起動する
GitHub ActionsでHerokuアプリを24時間稼働させる
Herokuの無料プランには30分間アクセスがないとアプリがスリープになるという仕様がある
これを回避する方法としてよく使われるのが、Heroku Schedulerを使ってcurlでリクエストを送るという方法
今回はHeroku Schedulerの代わりにGitHub Actionsでやってみた
手順 🔗
Workflowファイル(.github/workflows/curl.yml)を作ってmasterにpushするだけ
あとでログを見たときに、GitHub Actionsからのアクセスと判別できるようにアプリURLの末尾に?from-github-actions
を追加している
name: Wake up, Heroku
on:
schedule:
- cron: '*/30 * * * *'
jobs:
curl:
runs-on: ubuntu-latest
steps:
- name: curl
uses: wei/curl@master
with:
args: https://sampleapp-20200924.herokuapp.com/?from-github-actions
結果 🔗
きっちり30分毎っていうわけではないが、アクセスが来ていることが確認できた
これだとスリープになってしまう時があるので、実行間隔を10分か20分毎にした方が良さそう
$ heroku logs -n 300 |grep from-github-actions
2020-09-23T12:21:14.591652+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=e4428e0c-0c34-4afe-94a1-a32cbc2f7a85 fwd="40.75.17.64" dyno=web.1 connect=0ms service=28ms status=302 bytes=600 protocol=https
2020-09-23T12:36:53.459891+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=db5657b5-4916-426f-9405-e92acdb770fd fwd="52.242.94.164" dyno=web.1 connect=7ms service=12ms status=302 bytes=600 protocol=https
2020-09-23T13:15:28.404752+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=d5b79ece-7864-42ba-81dd-b7321fc375d9 fwd="52.255.157.44" dyno=web.1 connect=2ms service=6ms status=302 bytes=600 protocol=https
2020-09-23T13:35:07.454408+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=9e64c15f-1100-4d3b-97a8-e85a8bcb6ddb fwd="40.70.3.80" dyno=web.1 connect=1ms service=9ms status=302 bytes=600 protocol=https
2020-09-23T14:19:24.647876+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=8c26dc11-1b6b-43c6-a0b9-63a3a2bfdcc7 fwd="20.44.105.173" dyno=web.1 connect=2ms service=33ms status=302 bytes=600 protocol=https
2020-09-23T14:38:10.402018+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=c4abe4aa-1776-454b-8bbc-bccbcc3aec15 fwd="20.190.244.243" dyno=web.1 connect=0ms service=13ms status=302 bytes=600 protocol=https
2020-09-23T15:23:34.018761+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=fd04102e-d446-4ef2-a877-bef85efcba95 fwd="20.190.35.15" dyno=web.1 connect=0ms service=73ms status=302 bytes=600 protocol=https
2020-09-23T15:34:43.497876+00:00 heroku[router]: at=info method=GET path="/?from-github-actions" host=sampleapp-20200924.herokuapp.com request_id=a5223a4e-55ba-48de-a9b3-ba0e7c5a4596 fwd="13.68.113.165" dyno=web.1 connect=0ms service=20ms status=302 bytes=600 protocol=https
参考 🔗
「Failed to initialize, db service is unhealthy.」の原因と解決方法
GitHub ActionsでRSpecを動かしたくて公式ドキュメントっぽいものを読みながらやっていたがうまく動かなかった
actions/setup-ruby: Set up your GitHub Actions workflow with a specific version of Ruby
name: Rails Unit Tests
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
services:
db:
image: postgres:11
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6
- name: Build and test with Rake
env:
PGHOST: 127.0.0.1
PGUSER: postgres
RAILS_ENV: test
run: |
sudo apt-get -yqq install libpq-dev
gem install bundler
bundle install --jobs 4 --retry 3
bundle exec rails db:create
bundle exec rails db:migrate
bundle exec rails test
問題 🔗
「Initialize containers」のところでエラーを吐く
Failed to initialize, db service is unhealthy.
Herokuで使っているデータベースを有料プランへ切り替える(Hobby Basicプラン)
Herokuで運用しているアプリのデータベースが無料の範囲を超えてしまったので有料プランに変更した
無料のHobby Devプランから9$/monthのHobby Basicプランに変更する
Hobby Devプランは10,000レコードまでで、Hobby Basicプランは10,000,000レコードまで
単純にプランを変更するだけではなく、新しいデータベースを作成して、データをコピーする必要がある
ただ、たったの6ステップで終わるので比較的簡単
- 新しいデータベースを作成
- メンテナンスモードをオン
- 古いデータベースから新しいデータベースへデータをコピー
- データベースの切り替え
- 古いデータベースを削除
- メンテナンスモードをオフ
手順 🔗
0. 現在のデータベース状況を確認 🔗
$ heroku pg:info
=== DATABASE_URL
Plan: Hobby-dev
Status: Available
Connections: 0/20
PG Version: 11.8
Created: 2020-01-14 16:30 UTC
Data Size: 11.4 MB
Tables: 11
Rows: 12370/10000 (Above limits, access disruption imminent)
Fork/Follow: Unsupported
Rollback: Unsupported
Continuous Protection: Off
Add-on: postgresql-flexible-12541
1. 新しいデータベースを作成 🔗
$ heroku addons:create heroku-postgresql:hobby-basic
Creating heroku-postgresql:hobby-basic on ⬢ masamune-20200114... $9/month
▸ Release command executing: config vars set by this add-on will not be available until the command succeeds. Use `heroku releases:output` to view
▸ the log.
Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Created postgresql-flat-43568 as HEROKU_POSTGRESQL_CHARCOAL_URL
Use heroku addons:docs heroku-postgresql to view documentation
HEROKU_POSTGRESQL_CHARCOAL_URL
が追加されている
名前は適当につけられるらしい
既存のRailsプロジェクトにAdminLTEを追加して、Herokuにデプロイをしたらコケた
問題 🔗
既存のRailsプロジェクトにAdminLTEを追加して、Herokuにデプロイをしたらコケた
$ git push heroku master
...省略...
remote: [4/4] Building fresh packages...
remote: error /tmp/build_4fd7fe15/node_modules/admin-lte: Command failed.
remote: Exit code: 127
remote: Command: npm run plugins
remote: Arguments:
remote: Directory: /tmp/build_4fd7fe15/node_modules/admin-lte
remote: Output:
remote: /bin/sh: 1: npm: not found
remote: info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
...省略...
バージョン 🔗
- Rails: 6.0.3.2
- AdminLTE: 3.0.5
原因 🔗
とりあえずnpmがないらしい
AdminLTEを入れる前も必要なはずだったのにコケていなかった理由はわかっていない
解決方法 🔗
buildpacks:add
コマンドでNode.jsのビルドパックを追加してあげればいい
ただ、主要言語のビルドパックは最後に追加する必要がある(今回の場合はRubyのビルドパック)
現状はRubyのビルドパックが追加されている
$ heroku buildpacks
=== masamune-20200114 Buildpack URL
heroku/ruby
--index 1
オプションを付けて、Node.jsのビルドパックを1番目に追加する
$ heroku buildpacks:add --index 1 heroku/nodejs
Buildpack added. Next release on masamune-20200114 will use:
1. heroku/nodejs
2. heroku/ruby
Run git push heroku main to create a new release using these buildpacks.
1にNode.js、2にRubyのビルドパックが登録されている状態になっていればOK
Rails6にRSpec、FactoryBot、DatabaseCleanerを導入する
思考停止した導入方法のメモ
手順 🔗
Gemのインストール 🔗
group :development, :test do
...省略...
gem 'database_cleaner-active_record'
gem 'factory_bot_rails'
gem 'rspec-rails', '~> 4.0.1'
end
bundle install
RailsにRSpecをインストール 🔗
bundle exec rails generate rspec:install
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
設定 🔗
RSpec.configure do |config|
...省略...
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
参考 🔗
【RuboCop】grepとawkを使って楽に新しいCopを有効にする
問題 🔗
RuboCopを実行したら、以下のような警告が出るようになった
$ bundle exec rubocop
The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file:
- Lint/BinaryOperatorWithIdenticalOperands (0.89)
- Lint/DuplicateElsifCondition (0.88)
- Lint/DuplicateRescueException (0.89)
...省略...
- Style/RedundantFileExtensionInRequire (0.88)
- Style/SingleArgumentDig (0.89)
- Style/StringConcatenation (0.89)
For more information: https://docs.rubocop.org/rubocop/versioning.html
RuboCopのバージョン 0.89.1
新しく追加されたCopはデフォルトで有効にならないので、rubocop.ymlに設定を追加しないといけないらしい
これをちまちま設定していくのはたまにならいいけど、Rubocopの更新頻度が早いのでかなりめんどくさい
対策 🔗
grepとawkを駆使して、有効にする設定を出力するワンライナーを作った
あとはコピペするだけなので、だいぶ楽になった
$ bundle exec rubocop lib/ |grep ' - .\+\/.\+ (.\+)' |awk '{print $3 ":"} {print " Enabled: true"}'
実行結果 🔗
$ bundle exec rubocop |grep ' - .\+\/.\+ (.\+)' |awk '{print $3 ":"} {print " Enabled: true"}'
Lint/BinaryOperatorWithIdenticalOperands:
Enabled: true
Lint/DuplicateElsifCondition:
Enabled: true
Lint/DuplicateRescueException:
Enabled: true
...省略...
Style/RedundantFileExtensionInRequire:
Enabled: true
Style/SingleArgumentDig:
Enabled: true
Style/StringConcatenation:
Enabled: true
一括で有効にする方法 🔗
公式ドキュメントに新しいCopを一括で有効にする方法が書いてあった
まあそりゃあるよね
【Rails】Twitterログイン機能を実装する
RailsアプリにTwitterアカウントでログインできる機能を実装したのでメモ
Twitterアカウントでログインができればよかったので最低限の実装しかしていない
deviseを使うほどでもないので、omniauth-twitterだけ使った
バージョン 🔗
- ruby: 2.6.6
- rails: 6.0.3.2
- omniauth-twitter: 1.4.0
手順 🔗
デベロッパー登録と、アプリの作成をしてAPIキーを取得する 🔗
省略
Callback URLに
- http://127.0.0.1:3000/auth/twitter/callback
- http://localhost:3000/auth/twitter/callback
開発段階では必要ないが、最終的に本番URLも必要
GemfileにTwitterログイン用のGem追加 🔗
gem 'omniauth-twitter'
OmniAuthの設定ファイル作成 🔗
環境変数のTWITTER_API_CONSUMER_KEY
とTWITTER_API_CONSUMER_SECRET
に取得したAPIキーをセットする
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, ENV['TWITTER_API_CONSUMER_KEY'], ENV['TWITTER_API_CONSUMER_SECRET']
end
usersテーブルとUserモデル作成 🔗
idは自動採番ではなくTwitterが発行したユーザーIDにしたいので、オートインクリメントしないようにしている
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users, id: false do |t|
t.column :id, 'BIGINT PRIMARY KEY'
t.string :nickname, null: false
t.string :name, null: false
t.string :image, null: false
t.timestamps
end
end
end
ユーザーを保存する処理をモデルに追記 🔗
class User < ApplicationRecord
def self.create_or_update_from_auth(auth)
find_or_initialize_by(id: auth[:uid]).tap do |user|
user.update!(
nickname: auth[:info][:nickname],
name: auth[:info][:name],
image: auth[:info][:image],
)
end
end
end
ログイン、ログアウトの処理をするコントローラーを作成 🔗
class SessionsController < ApplicationController
def create
user = User.create_or_update_from_auth(request.env['omniauth.auth'])
session[:user_id] = user.id
flash[:notice] = 'ログインしました。'
redirect_to root_path
end
def destroy
reset_session
flash[:notice] = 'ログアウトしました。'
redirect_to root_path
end
end
ヘルパーメソッドを追加 🔗
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user, :logged_in?
private
def current_user
return unless session[:user_id]
@current_user ||= User.find(session[:user_id])
end
def logged_in?
!!session[:user_id]
end
end
ログイン、ログアウトのリンクを追加する 🔗
好きな場所に入れる
Gitのタブ補完を有効にする
Glide使ってNoCodeでアプリを作ってみる
巷で話題のNoCodeでアプリ作成をやってみたかったので、Glideを少し触ってみた
Glideとは 🔗
簡単に言うと、GoogleスプレッドシートをデータベースとしてノーコードでPWAサイトを作れるサービス
https://www.glideapps.com/
作成するアプリ 🔗
YouTubeに公開されている「香水 歌ってみた」シリーズを一覧で見れるアプリ
アプリURL 🔗
動画 🔗
アプリの作成手順 🔗
スプレッドシートでデータを作る 🔗
項目 🔗
- Video URL
- Video Title
- Thumbnail URL
投稿日、再生数の項目も欲しかったがノーコードでは厳しいと思ったので省略
Video URL 🔗
動画のURLをコピペで貼り付け
Video Title 🔗
関数で取得する
=SUBSTITUTE(IMPORTXML(A2,"/html/head/title")," - YouTube", "")
// IMPORTXMLで動画タイトルを取得
// IMPORTXML(サイトURL, XPathクエリ)
IMPORTXML("https://www.youtube.com/watch?v=9MjAJSoaoSo", "/html/head/title")
// => "香水 / 瑛人 (Official Music Video) - YouTube"
// SUBSTITUTEで「 - YouTube」を取り除く
// SUBSTITUTE(対象文字列, 検索文字列, 置換文字列)
SUBSTITUTE("香水 / 瑛人 (Official Music Video) - YouTube", " - YouTube", "")
// => "香水 / 瑛人 (Official Music Video)"
Thumbnail URL 🔗
関数で取得する
="https://i.ytimg.com/vi/"®EXEXTRACT(A2, "\?v=([^&]+)")&"/maxresdefault.jpg"
// REGEXEXTRACTで動画のURLからVideo IDを抽出
// REGEXEXTRACT(文字列, 正規表現)
REGEXEXTRACT("https://www.youtube.com/watch?v=9MjAJSoaoSo", "\?v=([^&]+)")
// => "9MjAJSoaoSo"
完成したデータベース 🔗
一旦データ量はこのくらい
青空文庫を縦書きで読むブックマークレット
別のものを作ろうした時にできた副産物だけど記録として残しておく
青空文庫
の小説を本らしく縦書きにする
ブックマークレット 🔗
javascript:(function(){const e=document.querySelector('.main_text');e.style.writingMode='vertical-rl';e.style.width='100%';e.style.overflow='scroll';})();
Before 🔗
これが
After 🔗
こうなる
もっと本らしく読めるウェブサービス 🔗
調べたら「えあ草紙
」という青空文庫の縦書き書籍リーダーがあった
色もそうだけど、裏のページの文字がちゃんと透けて見えるようになっていて再現度が高い
参考 🔗
Togglの作業時間をPixelaで可視化する
コロナの影響で在宅勤務なり、可処分時間が増えた
せっかく増えた時間を無駄にしないようにと自己研鑽に励み、その時間をTogglで管理している
さらに可視化をしたらモチベーション上がるかなと思ったので、Pixelaに草を生やしてみた
Lambdaでやろうとしたけど、僕はひよっこエンジニアなのでGASに逃げた
GASはコーディングから定期実行の設定までサクッとできるから便利(おそらくLambdaもそう)
仕様 🔗
- 毎日0時に前日分のTogglに記録された合計作業時間をPixelaに反映する
- Pixelaに草を生やす単位は分
コード 🔗
※ 最初のグラフを作成する手順は省略
function myFunction() {
const properties = PropertiesService.getScriptProperties().getProperties();
const date = new Date();
date.setDate(date.getDate() - 1);
const date_toggl = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy-MM-dd');
const toggl = new Toggl(properties.TOGGL_API_TOKEN);
const summary = toggl.fetchSummary('toggl_to_pixela', properties.TOGGL_WORKSPACE_ID, date_toggl, date_toggl);
const minutes = parseInt(summary['total_grand'] / 1000 / 60);
const pixela = Pixela.create(properties.PIXELA_USERNAME, properties.PIXELA_PASSWORD);
const date_pixela = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyyMMdd');
pixela.updatePixel('task-durations', date_pixela, minutes);
}
class Toggl {
constructor(apiToken) {
this.apiToken = apiToken;
}
fetchSummary(userAgent, workspaceId, since, until) {
const url = 'https://toggl.com/reports/api/v2/summary?' +
'user_agent=' + userAgent +
'&workspace_id=' + workspaceId +
'&since=' + since +
'&until=' + until;
const options = {
'method' : 'GET',
'headers': {'Authorization' : 'Basic ' + Utilities.base64Encode(this.apiToken + ':api_token')},
'muteHttpExceptions' : true,
}
const response = UrlFetchApp.fetch(url, options);
return JSON.parse(response);
}
}
特に細かい説明はしないけど、
- パスワード、トークンはPropertiesServiceを使って管理した
- Pixelaはライブラリがあったので使わせてもらった
- Togglはライブラリが見つからなかったので簡単なクラスを作成した
本来であれば例外処理などの対応をやっておいた方がいいが、
コケたらコケたでいいやと思ったのとスクリプトがコケた場合は、
Googleからメールが来るのでそれで十分と判断したため省略した
GASにおけるパスワード等の機密情報の取り扱い方
GASでパスワードやトークンなどをハードコーディングしたくなかったので、環境変数的なものに格納する方法を調べた
PropertiesServiceを使うといいらしい
使い方 🔗
値の登録 🔗
[ファイル]→[プロジェクトのプロパティ]→[スクリプトのプロパティ]
値の取得 🔗
PropertiesService.getScriptProperties().getProperty("ID");
// => hoge
PropertiesService.getScriptProperties().getProperty("PASSWORD");
// => test1234
一括取得 🔗
長いし、複数ある場合はgetProperties()
でまとめて取得するのが良さそう
const properties = PropertiesService.getScriptProperties().getProperties();
properties.ID // => hoge
properties.PASSWORD // => test1234
本来の使い方 🔗
キーバリューストアなので、スクリプトから値の保存や削除もできる
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty("key", "value"); // 保存
scriptProperties.getProperty("key"); // 取得
scriptProperties.deleteProperty("key"); // 削除
参考 🔗
【Rails】スコープとクラスメソッドの違い
普通に実装していたら違いなんてなくてどっちでもいいじゃんって思ってたけど、明確な違いがあった
今までたまたまそういう実装をしていないからハマらなかっただけで、いつかハマるかもしれないからメモしておく
スコープとクラスメソッドの違い 🔗
メソッドチェインができるようにスコープはActiveRecord::Relationを返すようになっている
どういう時にハマる可能性があるか 🔗
以下のようなfind_ageスコープを作成
class User < ApplicationRecord
scope :find_age, ->(age) { find_by(age: age) }
end
条件に一致するレコードがある場合は特に問題ない 🔗
[1] pry(main)> User.find_age(27)
User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`age` = 27 LIMIT 1
=> #<User:0x00007f3b4dc32b18
id: 1,
name: "takagi",
age: 27,
created_at: Sat, 08 Aug 2020 22:07:38 JST +09:00,
updated_at: Sat, 08 Aug 2020 22:07:38 JST +09:00>
条件に一致するレコードがない場合は全件返ってくる 🔗
[1] pry(main)> User.find_age(30)
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`age` = 30 LIMIT 1
=> User Load (0.2ms) SELECT `users`.* FROM `users`
[#<User:0x00007f3b4dd94448
id: 1,
name: "takagi",
age: 27,
created_at: Sat, 08 Aug 2020 22:07:38 JST +09:00,
updated_at: Sat, 08 Aug 2020 22:07:38 JST +09:00>,
#<User:0x00007f3b4dd94380
id: 2,
name: "tanaka",
age: 25,
created_at: Sat, 08 Aug 2020 22:07:53 JST +09:00,
updated_at: Sat, 08 Aug 2020 22:07:53 JST +09:00>,
#<User:0x00007f3b4dd942b8
id: 3,
name: "sato",
age: 32,
created_at: Sat, 08 Aug 2020 22:09:52 JST +09:00,
updated_at: Sat, 08 Aug 2020 22:09:52 JST +09:00>]
find_by
メソッドは条件に当てはまるレコードがないときはnilを返す仕様
スコープはActiveRecord::Relationを必ず返す仕様なので、nilではなくallと同じ結果のActiveRecord::Relationを返す
コアを吐いた
いつの間にかプロジェクトルートにcore.275
という名前のファイルが出来ていることに気づいた。
しかもrootだし、容量もでかい。怖い。
$ ls -la core.275
-rw------- 1 root root 236916736 7月 15 21:26 core.275
調べてみるとこれはどうやらコアファイルというらしい。
コアファイル 🔗
プログラムが異常終了した時に出力されるファイルのこと
異常終了直前のメモリの状態などが書き込まれている
「コアダンプファイル」とも呼ばれる
core.
のあとの数字はプロセスID
コアダンプ 🔗
コアファイルを出力すること
俗に「コアを吐く」という
どのプログラムがコアファイルを出力したかを確認する 🔗
file
コマンドで確認できる
$ sudo file core.275
core.275: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from 'spring app | app | started 25 hours ago | development mode', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/local/bin/ruby', platform: 'x86_64'
springがクラッシュしたみたいなので今回はこれ以上深追いはしなかった。
不要になったコアファイルは消して問題ないみたい。
参考 🔗
Toggl APIで前日の総作業時間を取得する
APIで取得できる項目はいろいろあるけど、前日の作業時間だけ欲しかったのでそれだけ調べたメモ
手順 🔗
API Tokenの取得 🔗
プロフィールページの下の方に表示されている
https://toggl.com/app/profile
curlで叩く 🔗
api_token
とworkspace_id
はドキュメントに載ってたダミー
curl -u 1971800d4d82861d8f2c1651fea4d212:api_token -X GET "https://toggl.com/reports/api/v2/summary?user_agent=api_test&workspace_id=123&since=2020-07-24&until=2020-07-24"
user_agent
: 必須。アプリケーション名かメールアドレスworkspace_id
: 必須。ReportsページのURLに含まれているsince
: 開始日(Defaults to today - 6 days.)until
: 終了日(Defaults to today, unless since is in future or more than year ago, in this case until is since + 6 days.)
結果 🔗
{
"total_grand": 6188000,
"total_billable": null,
"total_currencies": [
{
"currency": null,
"amount": null
}
],
"data": [
{
"id": 162312870,
"title": {
"project": "ブログ活動",
"client": null,
"color": "0",
"hex_color": "#d92b2b"
},
"time": 3777000,
"total_currencies": [
{
"currency": null,
"amount": null
}
],
"items": [
{
"title": {
"time_entry": ""
},
"time": 3777000,
"cur": null,
"sum": null,
"rate": null
}
]
},
{
"id": 162307142,
"title": {
"project": "英語学習",
"client": null,
"color": "0",
"hex_color": "#c9806b"
},
"time": 428000,
"total_currencies": [
{
"currency": null,
"amount": null
}
],
"items": [
{
"title": {
"time_entry": ""
},
"time": 428000,
"cur": null,
"sum": null,
"rate": null
}
]
},
{
"id": 162354173,
"title": {
"project": "読書",
"client": null,
"color": "0",
"hex_color": "#0b83d9"
},
"time": 1983000,
"total_currencies": [
{
"currency": null,
"amount": null
}
],
"items": [
{
"title": {
"time_entry": ""
},
"time": 1983000,
"cur": null,
"sum": null,
"rate": null
}
]
}
]
}
jqで総作業時間を取得 🔗
total_grand
が総作業時間(単位はms)
Pixelaを使ってみる
Pixela 🔗
あなたの頑張りや継続を記録し、育てたい。 そのすべてを、APIで。 Pixela はAPIサービスです。このサービスを使えば、あなたの日々の様々な活動量を GitHub のような鮮やかなグラフで表現することができます。 そのすべての操作を、APIで。もちろん、無料です。
Pixela | あなたの頑張りや継続を記録し、育てたい。そのすべてを、APIで。
使い方 🔗
たったの3ステップでできる
ユーザーの作成 🔗
$ curl -X POST https://pixe.la/v1/users -d '{"token":"password", "username":"takagi", "agreeTermsOfService":"yes", "notMinor":"yes"}'
- token: パスワード
- username: ユーザー名
- agreeTermsOfService: サービスの利用規約に同意したか
- notMinor: 未成年ではないか。未成年の場合、保護者の了承は得ているか
グラフの作成 🔗
$ curl -X POST https://pixe.la/v1/users/takagi/graphs -H 'X-USER-TOKEN:password' -d '{"id":"test-graph","name":"graph-name","unit":"commit","type":"int","color":"shibafu"}'
- X-USER-TOKEN: パスワード
- id: グラフのID
- name: グラフの名前
- unit: 記録する値の単位
- type: 記録する値の型
- int
- float
- color: グラフの色
- shibafu (緑)
- momiji (赤)
- sora (青)
- ichou (黄)
- ajisai (紫)
- kuro (黒)
作成したグラフ 🔗
値の登録 🔗
$ curl -X POST https://pixe.la/v1/users/takagi/graphs/test-graph -H 'X-USER-TOKEN:password' -d '{"date":"20200723","quantity":"5"}'
- date: 日付
- quantity: 値
値を登録したグラフ 🔗
nvmでdefaultを指定してもsystemのnodeが使われてしまう問題
マージ済みのブランチを一括削除する
Docker ComposeでRuby on Jetsの開発環境を構築する
Docker Composeを利用して、Ruby on Jetsの開発環境を構築してみる。
細かい設定はいろいろあるけど、とりあえず最低限のJetsの画面が表示される状態をゴールとする。
そもそもRuby on Jetsとは?
サーバーレスアプリケーションをRailsライクに作成できるRuby製のサーバーレスフレームワークのこと。
AWSへのデプロイも簡単らしい。
https://rubyonjets.com/
バージョン 🔗
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.6
BuildVersion: 17G11023
$ docker --version
Docker version 19.03.5, build 633a0ea
$ docker-compose --version
docker-compose version 1.25.4, build 8d51620a
手順 🔗
プロジェクトのディレクトリを作って移動 🔗
mkdir sample_jets_app
cd sample_jets_app
Dockerfileを作成 🔗
$ vim Dockerfile
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs yarnpkg mariadb-client
RUN ln -s /usr/bin/yarnpkg /usr/bin/yarn
RUN mkdir /sample_jets_app
WORKDIR /sample_jets_app
COPY Gemfile /sample_jets_app/Gemfile
COPY Gemfile.lock /sample_jets_app/Gemfile.lock
RUN bundle install
COPY . /sample_jets_app
CMD ["jets", "server", "--port", "3000", "--host", "0.0.0.0"]
Gemfileを作成 🔗
$ vim Gemfile
source 'https://rubygems.org'
gem 'jets'
空のGemfile.lockを作成 🔗
$ touch Gemfile.lock
docker-compose.ymlを作成 🔗
$ vim docker-compose.yml
version: '3'
services:
web:
build: .
command: bash -c "bundle exec jets server --port 3000 --host 0.0.0.0"
volumes:
- .:/sample_jets_app
- bundle_vol:/usr/local/bundle
ports:
- "3000:3000"
depends_on:
- db
db:
image: mysql:5.7
volumes:
- mysql_vol:/var/lib/mysql
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=1
volumes:
bundle_vol:
driver: local
mysql_vol:
driver: local
Jetsアプリケーションを作成 🔗
$ docker-compose run web jets new . --force --no-deps --database=mysql
$ docker-compose run web jets new . --force --no-deps --database=mysql
Creating network "sample_jets_app_default" with the default driver
Creating volume "sample_jets_app_bundle_vol" with local driver
Creating volume "sample_jets_app_mysql_vol" with local driver
Creating sample_jets_app_db_1 ... done
Building web
Step 1/10 : FROM ruby:2.5
---> 5a76bd71024b
省略...
Done in 138.88s.
================================================================
Congrats 🎉 You have successfully created a Jets project.
Cd into the project directory:
cd .
To start a server and test locally:
jets server # localhost:8888 should have the Jets welcome page
Scaffold example:
jets generate scaffold post title:string body:text published:boolean
jets db:create db:migrate
To deploy to AWS Lambda, edit your .env.development.remote and add a DATABASE_URL endpoint.
Then run:
jets deploy
Jetsアプリケーションに必要なファイルが生成されている
【Mac】pipでAWS CLIをインストールする
AWS CLIにはバージョン1とバージョン2があるらしい。今回はバージョン1を入れた時のメモ。
バージョン 🔗
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.6
BuildVersion: 17G11023
$ pip3 --version
pip 19.3.1 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)
手順 🔗
pip3でAWS CLIをインストール 🔗
pip3 install awscli --upgrade --user
PATHを通す 🔗
インストールしただけだとそんなコマンドないよと怒られる
$ aws
-bash: aws: command not found
# vim ~/.bash_profile
export PATH=~/Library/Python/3.7/bin:$PATH
source ~/.bash_profile
正しくイントールをされたか確認する 🔗
$ aws --version
aws-cli/1.18.11 Python/3.7.6 Darwin/17.7.0 botocore/1.15.11
完璧だね!
参考 🔗
macOS に AWS CLI バージョン 1 をインストールする - AWS Command Line Interface
Macでcrontabに登録した時に出た「crontab: "/usr/bin/vi" exited with status 1」の対応
RailsアプリをHerokuにデプロイする際にrails db:migrateも一緒に実行するようにする方法
やったこと 🔗
RailsアプリをHerokuにデプロイする際に、db:migrate
も一緒に実行するようにした。
デプロイした面倒だし、忘れることもあるので一緒に実行してくれたらいいのになと思ったらProcfileに書けばいいらしい。
やり方 🔗
設定 🔗
Procfileにrelease: rails db:migrate
を追記。
# Procfile
web: bundle exec puma -C config/puma.rb
release: rails db:migrate
動作確認 🔗
$ git push heroku master
~~ 省略 ~~~
remote: Running release command...
remote:
remote: D, [2019-12-23T06:57:47.260162 #21] DEBUG -- : (5.4ms) SELECT pg_try_advisory_lock(4073851584526618965)
remote: D, [2019-12-23T06:57:47.318112 #21] DEBUG -- : (5.9ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
remote: D, [2019-12-23T06:57:47.338659 #21] DEBUG -- : ActiveRecord::InternalMetadata Load (3.4ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2 [["key", "environment"], ["LIMIT", 1]]
remote: D, [2019-12-23T06:57:47.350521 #21] DEBUG -- : (1.8ms) BEGIN
remote: D, [2019-12-23T06:57:47.356765 #21] DEBUG -- : (3.7ms) COMMIT
remote: D, [2019-12-23T06:57:47.358866 #21] DEBUG -- : (1.8ms) SELECT pg_advisory_unlock(4073851584526618965)
remote: Waiting for release.... done.
~~ 省略 ~~~
ちょうどタイミングよく新しいマイグレーションがなかったので出来てるって感じはしないけど、ちゃんと動いてるっぽい。