ポンコツ.log

ひよっこエンジニアのちょっとしたメモ。主に備忘録。たまに雑記。

【jQuery】animateでアコーディオン

フロントは苦手です。

アコーディオンの実装ならslideToggle
となるのですが、一部だけ残して下の部分が展開するタイプのアコーディオン(そもそもアコーディオンと言うのかも怪しい…)を実装しようとすると、 slideToggle だと「一部を残す」ができなかったので、animateアコーディオンっぽい動きを作りました。

See the Pen accordion by s-mori (@s-mori) on CodePen.

slideToggle([speed], [callback]) - jQuery 日本語リファレンス
animate(params, options) - jQuery 日本語リファレンス

scrollHeightで展開時の高さを指定

resizeHeight = target.get(0).scrollHeight
target.animate({"height": resizeHeight})

scrollHeightoverflow 部分を含めた高さを取得し、その値を height で指定しています。
target.animate({"height": "100%"}) としても展開はされるのですが、この場合 animate が効かなくなります。

.scrollHeight | JavaScript 日本語リファレンス | js STUDIO

data属性を利用して元の高さに畳む

target.attr('data-org-height', target.innerHeight())

展開する前に、元の高さを取得して、 data属性を利用して保持させます。

orgHeight = target.attr('data-org-height');
target.animate({"height": orgHeight});

畳む時は、 data属性として持たせていた高さを取得し、 animate に渡します。
元の高さ(上記penの場合だと60px)を指定しても問題はないのですが、SP等で高さが変わるときにブラウザ判定を入れたくなかったので、悩んだ挙句、data属性を利用しています。

data便利ですぐ使ってしまう…。

slideToggleでできる方法もあるのかもしれない…)

【shell】今年はfish、キミに決めた

1月に1本でも上げようと思っていたらもう2月でした。
今年は更新頑張ろうと思いながら、すでに雲行きが怪しいです。

私事ですが転職をしまして、今年から新たなところでお世話になっています。
当然仕事に使うPCも代わり、まっさらな状態に戻ったので、ゴリゴリ環境を整えていたわけですが、「シェルどうしようかなぁ…」と迷っていました。

過去2回、元同期にオススメされたpreztoを導入してきたのですが、頭が足りないということもあって、どうにもすんなりいかない。
エディタが永遠にnanoになるという呪いにかかり、1から入れ直しということも経験してきました。
そんなこともあってか若干のprezto恐怖症を抱えていたので、潔く他のものにしてみようと思い立ち、良さげと聞いたfishを導入しました。

fishshell.com

fish導入

fish インストール

fishサイトの「Go fish」のところにインストール方法があります。
MacではHomebrewが使えるようなので、サクッとbrew installします。

$ brew install fish
$ fish -v
fish, version 2.7.1

fishをデフォルトに変更

インストールは無事完了したので、デフォルトのシェルをfishに変更します。
/etc/shellsにシェルの一覧が記述されているので、その中にfishのフルパスを追記します。

$ sudo vi /etc/shells
# /usr/local/bin/fish 追加

fishが利用できるようになったので、chshコマンドでデフォルトをfishに変更します。

$ chsh -s /usr/local/bin/fish
Changing shell for USERNAME.
Password for USERNAME:

終わりました。はやい \\٩('ω')و//

fishermanインストール

github.com ついでにプラグインマネージャの「fisherman」なるものも入れます。
他のプラグインマネージャの比較はこちらが参考になります。
fishのプラグインマネージャ比較 - Qiita

fishermanリポジトリにあるInstallの通り進めます。

$ curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs https://git.io/fisher

# 一度ターミナルを再起動
$ fisher -v
fisherman version 2.13.2 ~/.config/fish/functions/fisher.fish

はやい \\٩('ω')و//

fisherコマンド

プラグインをインストールするときは

$ fisher plugin

インストール済みプラグイン一覧を見るときは

$ fisher ls

プラグインを更新するときは

$ fisher up [plugin]

インストールしたプラグインを削除するときは

$ fisher rm [plugin]

という感じで使えるようです。

テーマ

テーマってなんだか見るだけでも楽しいんですよね。
今回はoh-my-fishの中にあるテーマから選びました。

「どれにしようかなー」と各テーマを眺めていると、見覚えのあるアイツがいました。
水属性の2まいがいポ●モン。

サ●シの気持ちになって「キミに決めた!」の勢いでshellderを入れます。
github.com

ちゃんと勢い以外でも選んでます。

テーマインストール

fishermanのおかげで、テーマの導入もぱぱっとできます。

# shellderインストール
$ fisher simnalamburt/shellder

フォントインストール&変更

f:id:mr_96:20180205171731p:plain このままでは豆腐フォントのままなので、フォントを入れて、ターミナルの設定を変更します。

フォントのインストールは、shellder#Fontsにあるフォント2種類を入れます。
一つはpowerline
こちらはgitから。

$ mkdir plugins
$ git clone git@github.com:powerline/fonts.git
$ cd fonts
$ ./install.sh

もう一つはnerd-fonts。 こちらはいくつかインストール方法があるようですが、サクッとbrewで入れてしまいます。

$ brew tap caskroom/fonts
$ brew cask install font-hack-nerd-font

iTerm2ユーザなので、iTerm2の Preferences > Profiles > Text > Font からフォントを変更します。 f:id:mr_96:20180205172619p:plain

f:id:mr_96:20180205173615p:plain 無事豆腐も解消 \\٩('ω')و//

つぶやき

導入して1ヶ月ほど経ちますが、今の所特に不満もなく、「補完アザァッス」な気持ちで過ごしています。
fish_configと叩けば設定画面が開くのも面白いです。
とはいえ他のと比べて何が良いの、とまではまだわからないレベルなので、もう少し使い込んでみたいと思います。

参考

詳解 fishでモダンなシェル環境の構築(fish,tmux,powerline,peco,z,ghq,dracula) - Qiita
fish shell を使いたい人生だった | Developers.IO

【Rails】rubocopを変更を加えたファイルに限定して実行する

コーディングルールをチェックしてくれるrubocopですが、途中から導入すると、ほとんどの場合ほぼ全ファイル修正する必要があるため、修正をやり遂げる前に力尽きます。
気合いで完遂したとしても、その量のレビューはちょっと辛く思ってしまったり。なんだり。
とりあえずは、自身が修正を加えたファイルに対してrubocop修正もできれば、修正祭は避けられます。

ということで、変更ファイルに限定して実行するようにしました。

git diffの結果に対してrubocop

修正を加えたところはgit diffで取得できます。

git diffだけでは差分の範囲なども表示してくれますが、rubocopで指定したいのはファイルなので、差分はファイル名で欲しいです。
なので、git diff--name-onlyオプションを追加して、ファイルのみ取得します。
rubocop実行のところはxargsで。

$ git diff --name-only | xargs bundle exec rubocop

削除ファイルは対象にしない

また、git管理されていたファイルを削除した場合、差分としては取得できるものの、そのままrubocopを実行するとno such fileと言われてしまいます。
「削除したファイルは差分として取得しなくても良い」として、差分取得時に--diff-filterオプションで、変更したファイルに限定します。

$ git diff --diff-filter=ACMR --name-only | xargs bundle exec rubocop

diff-filterに指定しているACMRは、それぞれ
- A…Added
- C…Copied
- M…Modified
- R…Renamed
です。

差分がなければ実行しない

git diff --diff-filter=ACMR --name-onlyの結果、差分がないとbundle exec rubocopが実行され、全ファイルがrubocopチェック対象になります。
これでは今までゴニョゴニョしてきたオプションが水の泡。rubocopに怒られまくります。

差分がなければrubocopを実行しなければ良いので、xargsの-r, --no-run-if-emptyオプションを使います。

$ git diff --diff-filter=ACMR --name-only | xargs --no-run-if-empty bundle exec rubocop

(xargs -r bundle exec rubocopでも)
Mac上で実行するときは、--no-run-if-emptyをつけると「そんなオプションありません!」と怒られます。
オプションをつけずにxargs bundle exec rubocopのままでも、差分がなければ実行しないようになっているようです。

【Docker】サクッとWordPress立ち上げメモ

サクラの簡単インストールでWordPressをインストールし、破壊し、というのを2回ぐらい繰り返しました。
おとなしくローカルで遊んでからにしよう…と思い、せっかくなのでDockerでローカル環境を作ろうと思い立ち、今に至ります。
公式のドキュメントにあるので完全備忘録です。
クイックスタート・ガイド:Docker Compose と Wordpressを参考に進めます。

docker-compose.yml用意

適当なWordPressプロジェクトのディレクトリを作って移動します。

$ mkdir wp_prj
$ cd wp_prj

作成したwp_prjディレクトリの中に、コンテナを立ち上げるためのdocker-compose.ymlを作ります。内容はクイックガイドのものを丸っと。

# docker-compose.yml
version: '2'
services:
  db:
    image: mysql:5.7
    volumes:
      - "./.data/db:/var/lib/mysql"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: wordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    links:
      - db
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_PASSWORD: wordpress

dbwordpressの2つのコンテナを作っています。

docker-composeの内容はこちらの記事がわかりやすかったです。ありがたい…。
参考:Docker Compose - docker-compose.yml リファレンス - Qiita

立ち上げ

docker-compose.ymlの準備ができたら、あとはコマンド一つだけです。

$ docker-compose up

docker-compose up -dのようにdオプションをつけるとデーモン起動)

念のためプロセス確認すると↓のようになります。

$ docker-compose ps
       Name                     Command               State          Ports
----------------------------------------------------------------------------------
wpprj_db_1          docker-entrypoint.sh mysqld      Up      3306/tcp
wpprj_wordpress_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:8000->80/tcp

立ち上がっている状態だと、docker machineを使っている場合はマシンIPでブラウザからアクセスできるようです。
特に何も使っていなければlocalhostでアクセスできるはずです。
今回はdocker machineを使っていないのでlocalhostで。 f:id:mr_96:20171022231417p:plain

無事セットアップ画面まで来れました。まだ破壊してません。

【Rails】omniauth-yahoojpのエラー対応

omniauth-yahoojpを使ってYahoo!IDでの認証を実装しているサービスで、いつのまにかエラーを吐き出すようになっていました。
さっとググって出てくるものと、ささっとググるだけでは出て来ないものがあったので、対応メモ。

invalid_redirect_url

まずはこちらのエラー。

ERROR -- omniauth: (yahoojp) Authentication failure!
  invalid_credentials: OAuth2::Error, invalid_redirect_uri: redirect_uri is invalid.

調べてみるとyahoojpではなく、omniauth-oauth21.4.0以降のエラーらしく、「omniauth-oauth2のバージョンを1.3.1にすれば解決できるよ」な記事をよく見かけます。
もしくはomniauth-oauth2のcallback_urlメソッドを上書きでも良いようです。
今回はomniauth-oauth2のバージョンを1.3.1に下げることで対応。

参考:
Gem omniauth-oauth2 バージョン1.4.0のエラー - Kntmrkm.new OmniAuth OAuth2 1.4.0 以降で `Invalid Credentials` エラー - Qiita

invalid_request: the parameter is invalid. [“client_id”]

この時点で、最初に出ていた「invalid_redirect_url」は解消されたように見えます。
が、今度はまた別のエラーが発生していました。

ERROR -- omniauth: (yahoojp) Authentication failure!
  invalid_credentials: OAuth2::Error, invalid_request: the parameter is invalid. ["client_id"]
{"error":"invalid_request","error_description":"the parameter is invalid. [\"client_id\"]","error_code":"102"}

こちらも調べてみると、今度はoauth2のv1.3.0で変更のあったパラメータを、yahoojpのGemにも追加しないといけないようです。

すでにmikanmarusan/omniauth-yahoojp#4の PRで取り込まれているようなので、この修正を反映すべく、omniauth-yahoojpのGemをアプデします。

$ bundle update omniauth-yahoojp

v0.1.4へのアプデが完了したところで再度確認すると、無事、Yahoo!IDでの認証ができるようになりました。

【Redis】メモリ周りの確認

Redisのメモリを使い切った時に「OOM command not allowed when used memory > ‘maxmemory’.」というエラーが発生することがあります。
「maxmemory言われてるし…」とメモリ周りを確認することになるので、ちらっと調べたことのメモ書き。

現時点でのメモリ使用量を調べる

RedisのinfoコマンドでRedisの情報を確認。
「メモリ情報だけ確認したい!」という時はinfo memoryで確認できます。

> redis-cli -h xxx
xxx:6379> info memory

# Memory
used_memory:1346349472
used_memory_human:1.25G
used_memory_rss:1322913792
used_memory_peak:1347333880
used_memory_peak_human:1.25G
used_memory_lua:36864
mem_fragmentation_ratio:0.98
mem_allocator:jemalloc-3.6.0

used_memoryが使用量(_humanで単位付き)なので、上記の例だと1.25Gのメモリを使用していることになります。

参考:
INFO – Redis

maxmemory-policyの確認

ざっくり言うと、「メモリいっぱいになったらどうする?」の設定。

  • noeviction
    メモリ制限に達しているのに、さらにメモリを使用するようなコマンド(ほぼ書き込み。DELやいくつか例外あり)を実行しようとしているときにエラーを返す。
  • allkeys-lru
    新しいデータの領域を確保するため、あまり使われていないキー(LRU)を先に削除しようとする。
  • volatile-lru
    新しいデータの領域を確保するため、あまり使われていないキー(LRU)を先に削除しようとする。有効期限が設定されているキーのみ対象。
  • allkeys-random
    新しいデータの領域を確保するため、キーをランダムに削除する。
  • volatile-random
    新しいデータの領域を確保するため、キーをランダムに削除する。有効期限が設定されているキーのみ対象。
  • volatile-ttl
    新しいデータの領域を確保するため、有効期限が設定されたキーの中で、より短い有効期間(TTL)のキーを削除する。

volatile-lruvolatile-randomvolatile-ttlを設定していても、有効期限を設定しているものが無い場合はnoevictionと同じ挙動になるので、メモリを使い切った時には例の「maxmemory」エラーが出てしまうようです。

参考:
Using Redis as an LRU cache – Redis

対策

有効期限を設定できるのであればそれが無難なような感じもしますが、時と場合によっては期限を設定したく無い時も。
そうなるとメモリの増量が有力候補に踊り出るかと思います。
AWSのElastiCacheの場合はノードタイプを変更することでメモリを増やすこともできますが、一時的に読み・書きができなくなるので、「アクセスできなくなったらまずいんだよなぁ…」な場合は、気持ち慎重に対応する必要があります。

参考;
単一ノード Redis のクラスターのスケールアップ - Amazon ElastiCache Redis 本番障害から学んだコードレビューの勘所 - Qiita Redisのメモリ使用量がmaxを超えた場合の挙動 - Gaishimo

【Serverspec】sidekiqのプロセスを確認する

Serverspecをちょこちょこ書いていて、sidekiqのプロセス確認をするコードを書いた時に
「sidekiqのプロセスも、リソースタイプのprocessで一発!」
と思ったら一発で仕留められなかったので、メモ。

processでsidekiqのプロセスを確認

processを使ってsidekiqの確認をした時のコード。

# sidekiqのプロセス確認
describe process('sidekiq') do
  it { should be_running }
end

これを実行すると、下記のようなエラーになりました。

Failures:

  1) Process "sidekiq" should be running
     On host `0.0.0.0'
     Failure/Error: it{ should be_running }
       expected Process "sidekiq" to be running
       sudo -p 'Password: ' /bin/sh -c ps\ -C\ sidekiq\ -o\ pid\=\ \|\ head\ -1

$ps -ef | grep sidekiqで確認する限りでは取得できていたので、「なんでかなー」と思っていたところ、

コマンド名とプロセス名が一致していない場合はリソースタイプ process を利用することが出来ない。
Serverspecでリソースタイプ process や package が使えない場合とその対処 - Qiita

とのこと。
改めて確認してみると、 $bundle exec sidekiqで起動していたので$ ps -C bundleでプロセスが確認できました。
ただ、これで確認するのもなぁ…という感じもするので、commandを使うことに。

commandでsidekiqのプロセスを確認

いつもプロセス確認する時のコマンドで確認しています。

describe command('ps -ef | grep [s]idekiq') do
  let(:disable_sudo) { true }
  its(:exit_status){ should eq 0 }
end

これを実行すると…

Command "ps -ef | grep [s]idekiq"
  exit_status
    should eq 0

無事成功。

何かと「うまくいかなかったらcommandで…」みたいに思ってしまうけれども、果たしてこれで良いのかどうか…。
悩みどころです。

『俳句の図書館』を読んで17音の意味を探る

少し前に書店で気になっていた本を買い、読み終わったところでいてもたってもいられず、とりあえずここに。

俳句の図書室 (角川文庫)

俳句の図書室 (角川文庫)

続きを読む

【nginx】ホスト名指定でのリバプロはresolverをセットで

nginxのリバースプロキシ設定で、転送先をIPではなくホスト名で指定していると、ある日突然エラーが発生する現象に遭遇しました。
ググると複数の記事が見つかったので、よくある現象?のようです。

リバースプロキシ設定

元々は↓のように設定していました。
proxy_passのところで、リクエストの転送先をホスト名で指定しています。

location ~ ^/hoge {
  proxy_pass https://example.com;
}

この状態だとnginx起動時に転送先のIPがキャッシュされ、以降はキャッシュしたIPへ転送するようになるようです。
IPが変わってもキャッシュしているIPへ転送し続けるので、AWSのELBを使っていたりすると、IPが変わった際にエラーが起きてしまうことも。
それを回避するため、proxy_passと併せてresolverを設定しておきます。

resolverを設定する

resolverを設定すると↓のような感じに。

location ~ ^/hoge {
  resolver 10.0.0.2;
  set $host_name example.com;
  proxy_pass https://$host_name;
}

resolverで指定するDNSのIPは、AWSの場合はVPCのネットワーク範囲+2とのこと。

AmazonProvidedDNS は Amazon DNS サーバーです。このオプションは、VPC のインターネットゲートウェイを介して通信する必要があるインスタンスに対して DNS を有効にします。文字列 AmazonProvidedDNS は、リザーブド IP アドレスで実行中の DNS サーバーにマップされ、VPC IPv4 ネットワークの範囲に 2 をプラスした値です。例えば、10.0.0.0/16 ネットワークの DNS サーバーの位置は 10.0.0.2 となります。
DHCP オプションセット - Amazon Virtual Private Cloud

デフォルトではTTLが切れたタイミングでDNSに問い合わせ。
resolverにvalidを設定すると、任意のタイミングで問い合わせることができるようです。
ex. valid指定

location ~ ^/hoge {
  resolver 10.0.0.2 valid=5s; # 5秒ごとに問い合わせ
  set $host_name example.com;
  proxy_pass https://$host_name;
}

nginxのバージョンによる?のか、nginx 1.6系、1.8系ではsetでホスト名を変数に入れないとエラーになるようです。
nginx 1.10.1では、setを使わずに指定しても設定できました。

参考

nginx proxy の名前解決問題、ファイナルアンサー? – 1Q77
Nginx のDNS 名前解決とS3 やELB へのリバースプロキシ :: by and for engineers
Nginxでproxy_passにホスト名を書いた時の名前解決のタイミング - (ひ)メモ

【Git】ブランチを切り替えた時にSlack通知されるようにした

開発に入ると、あとから「あれ、時間どれくらいかかったっけ」みたいになることありませんか。
自分はしょっちゅうありまして、Togglを使うようにしたものの、開始/終了忘れが続出。
作業を変更するタイミングで勝手にどこかに記録されていった方が良いなーと思って、開発中は何度も行うブランチの切り替えをタイミングにしてみることにしました。

checkoutのタイミング

「はて、checkoutのタイミングってどうやって知るんだろう」
ちょろっと調べるとすぐに出てきました。

git checkoutが正常に終了すると、post-checkoutフックが実行されます。
8.3 Git のカスタマイズ - Git フック#その他のクライアントフック

.git/hooksの中にはいくつかサンプルがあります。
その中にpost-checkoutファイルを作って処理を書いておくとcheckout後に実行されるらしいので、これを利用することにします。

ブランチ名の取得

「はて、ブランチ名ってどうやって取得するんだろう」
これもちょっと調べると出てきました。

git rev-parse --abbrev-ref HEADでできるらしい。rev-parse初めて知りました。
gitで現在のブランチ名を取得する - 技術は熱いうちに打て!

後から調べたのですが、Git1.8以降であればgit symbolic-ref --short HEADでも取得できるようです。
Gitリポジトリのカレントブランチ名を取得する | blog: takahiro okumura

現在のブランチ名がgit rev-parse --abbrev-ref HEADなら、一つ前はgit rev-parse --abbrev-ref @{-1}かな?と思って試したら、ちゃんと前のブランチ名を取得できました。
ということで、

# 現在のブランチ名を取得
$ git rev-parse --abbrev-ref HEAD
master

# 前のブランチ名を取得
$ git rev-parse --abbrev-ref @{-1}
develop

git rev-parseなかなか面白い。
git rev-parseを使いこなす - Qiita

最終的に

↓のように着地。

Slackへの通知は[10分で出来る]シェルスクリプトの結果をslackに投稿 - Qiitaを参考にしています。

実際にmaster -> developへブランチを変更すると… f:id:mr_96:20170603233338p:plain キタ(゚∀゚)!
名前(gittn)やメッセージは整えるとして、とりあえず通知するところまでは完了。
これでSlack上で切り替えた時間がわかるので、大まかにでも作業時間がわかる(はず)。

curl叩いている分、checkoutが若干遅くなってしまったのは…どうしよう…。