Rails でレコード数の多いテーブルを雑に抽出する

conn = ActiveRecord::Base.connection
conn.select_all('show tables').rows.flatten.
  map {|table| [table, conn.select_all("select count(1) from #{table}").rows.flatten.first] }.
  sort_by {|_, c| -c }.
  take(10)

Raspberry Pi の無線 LAN の設定までした

長らく(1年半…)放置していたがついに重い腰を上げた。始めたら30分程度で出来たし、もっと早くやっておけばよかった…

参考にした記事: raspberry pi2 で 無線 LAN 設定まで

macOS Sierra にアップデートした

Karabiner が使えなくなるから…とアップデートを避けていたが、 Karabiner の設定を確認してみるとキーリマップは全部⌘英かなで代替できるものだったのと、キーリピート速度もコマンドで変更できることが分かったのでアップデートした。

現在のキーリマップは以下の3つのみ。

  • 左右のコマンドキーを単発押しで英数/かなキーに
  • 左のコントロールキーを単発押しで Esc に
  • Ctrl+j で改行

また、キーリピート速度はMacのキーリピート速度とキーリピート開始速度をカスタマイズする方法を参考に、ターミナルで以下のようにコマンドを実行して変更した。

# 現在のキーリピート速度を表示
defaults read -g KeyRepeat
# 現在のキーリピート開始速度を表示
defaults read -g InitialKeyRepeat

# キーリピート速度を1に設定(小さい程速い)
defaults write -g KeyRepeat -int 1 # 15ms
# キーリピート開始速度の早さを10に設定(小さい程早い)
defaults write -g InitialKeyRepeat -int 10 # 150ms

# キーリピート速度をデフォルトに戻す
defaults delete -g KeyRepeat
# キーリピート開始速度をデフォルトに戻す
defaults delete -g InitialKeyRepeat

# 反映には Mac の再起動が必要

愛を伝え続けるために

この記事は妻・夫を愛してるITエンジニア Advent Calendar 2016の6日目です。

属性

  • 私: Web 系プログラマ
  • 妻: Web 系デザイナ(同じ職場)
  • 子供: 3歳の娘と1歳の息子

本題: 妻を愛してる…けど

私は妻を愛しています。

日頃からそれを伝え続けたいと思っているわけですが、 余裕がないと気持ちを伝える時間がとれなかったり、些細なことですれ違ったりして愛を伝えることが難しくなります。

これからの長い時間を一緒に過ごしていくつもりなのですから、余裕を確保しておくのは大事です。

単一障害点の排除と負荷分散

どちらか片方が病気になって倒れたりしたら家庭の運営が行き詰まる(ex. ご飯作り)ようだと、万一のときに詰んでしまって余裕どころではありません。冗長化します。 また、冗長化できたらそのまま負荷を分散させておきます。

具体的には以下のようなことをしました。

  • 家事全般をどちらでもできるように(ほぼ私の料理、育児スキルアップ)
  • 晩ご飯の献立を共有してどちらでも晩ご飯作りを担当できるように
  • 買い物リスト、その他の家庭のタスクは Wunderlist で共有してどちらでもできるように
  • (保育園などの)書類は写真撮って Google フォトで共有
  • 保育園の伝達事項も家庭内 Slack に投稿して検索できるように
  • Google カレンダーで予定を共有(それぞれの予定、家族の予定)

共有と(私の)レベル上げですね。

結果、妻が一週間程度ダウンしたときもなんとか乗り切れました 💦

負荷の軽減

負荷も減らせるところから減らして余裕を作っていきます。がんばらない 💪

  • 洗濯乾燥機を購入して干す時間の削減 && 天気、時間を気にしないですむのでストレス削減
  • 食材は主におうちコープ(たまにイオンネットスーパー)で購入して買い物の時間削減
  • 朝食は基本は固定メニュー(土日に違うもの)で朝食準備の負荷を固定
  • 定期的に購入するものは Amazon 定期便に寄せて気にしなくて済むように
  • 消耗品は Amazon で購入できるものを優先して買い足しを楽に
  • ルールや共有事項は文書化して LINE のノートに共有。記憶しなくていいように & 言った言わないのトラブルを避ける
  • 献立は履歴を残してあとで参考にできるように

今はスペースの都合で出来てないのですが次引っ越すときには食洗機も絶対導入するぞ…!と二人で決めています。

あと勤務先のお陰で週3日は自宅からリモートで勤務できるのが大きいです。

同じ目標

余裕とは少し違うのですが、そもそもなんのために?がないと厳しいですよね。

例えばお金ですが、出来るだけ公平に && がんばりが報われるようなやり方でお金を扱いたいと思っています。

以前は給与が上がると自分が自由に使える額が増える 💴 インセンティブ設計だったのですが、 最近、定額のお小遣い + 家用の予算から余った分をインセンティブとして二人で分け合うやり方に変えました。

バージョンアップして以前より同じ目標を見れるようになった気がします。

まとめ

  • 冗長化していざというときに備えつつ負荷分散し、
  • 減らせる負荷を減らし、
  • 共通の目標をもつように

して出来た余裕と心の結びつきで、今日も妻に愛してると言えるわけです。

もちろん、これからも変わらず。

Rails 5.1 から time 型の列もタイムゾーン考慮するようになるとのこと

経緯

Rails 5 で time 型の列をもつレコードを操作していたところ、以下のようなメッセージが表示された。

DEPRECATION WARNING: Time columns will become time zone aware in Rails 5.1. This
still causes `String`s to be parsed as if they were in `Time.zone`,
and `Time`s to be converted to `Time.zone`.

To keep the old behavior, you must add the following to your initializer:

    config.active_record.time_zone_aware_types = [:datetime]

To silence this deprecation warning, add the following:

    config.active_record.time_zone_aware_types = [:datetime, :time]
 (called from require at bin/rails:4)

Rails 5.1 からデフォルトの挙動が変わるからねー、ということらしい。

Time columns will be aware of application time zone In Rails 5.1 your time columns will adhere to the time zone of your Rails application. To make the upgrade path smoother, the config.active_record.time_zone_aware_types option has been added. See the deprecation warning here for help.

http://weblog.rubyonrails.org/2015/1/16/This-week-in-Rails-tokens-migrations-method-source-and-more/

該当のPR: https://github.com/rails/rails/pull/15726

何が変わるのか

create_table "foos", force: :cascade do |t|
  t.time "start_at"
end
= form_for @foo do |f|
  = f.time_field :start_at
  = f.submit

なときに、「09:00」と入力して submit すると

Parameters: {"foo"=>{"start_at"=>"09:00"}}

のようなパラメータでリクエストが飛ぶ。

このとき、

今までの挙動

config.time_zone = 'Tokyo'
config.active_record.time_zone_aware_types = [:datetime]

だと

irb(main):001:0> Foo.first
#<Foo id: 1, start_at: "2000-01-01 09:00:00", created_at: "2016-07-18 04:07:26", updated_at: "2016-07-18 04:07:26">
irb(main):002:0> Foo.first.start_at
=> 2000-01-01 09:00:00 UTC

のように UTC で 9:00 だったのが、

新しい挙動

config.time_zone = 'Tokyo'
config.active_record.time_zone_aware_types = [:datetime, :time]

だと

irb(main):001:0> Foo.first
#<Foo id: 1, start_at: "2000-01-01 00:00:00", created_at: "2016-07-18 04:07:26", updated_at: "2016-07-18 04:07:26">
irb(main):002:0> Foo.first.start_at
=> Sat, 01 Jan 2000 09:00:00 JST +09:00

のように JST で 9:00 になる。

対応

Deprecation warning 抑えるためには適当な initializer 内(config/application.rb とか)で config.active_record.time_zone_aware_types を設定する。

既存の挙動(タイムゾーン考慮しない)を保つ場合は

config.active_record.time_zone_aware_types = [:datetime]

新しい挙動(タイムゾーン考慮する)にする場合は

config.active_record.time_zone_aware_types = [:datetime, :time]

にする。

Yokohama.rb Monthly Meetup #70 :: どう書く

Yokohama.rb Monthly Meetup #70に行って「どう書く」に挑戦してきた。

問題はこれで、自分の回答は下に記載。 回答時間は20分いかないぐらいだったと思うんだけど、競技プログラミング勢なら10分かからないだろうとのこと。

もっとキレイに書きたかった & 1次元配列 + 番兵での回答は思いつきもしなかったので悔しみがある。

class Walker
  attr_reader :dir, :point

  def initialize(point)
    @point = point
    @dir = 'd'
    @ended = false
  end

  def ended?
    @ended || i < 0 || i > 3 || j < 0 || j > 3
  end

  def i
    point[0]
  end

  def j
    point[1]
  end

  def move(type)
    case type
    when 0
      case dir
      when 'r' then up
      when 'u' then right
      when 'l' then down
      when 'd' then left
      end
    when 1
      case dir
      when 'r' then down
      when 'u' then left
      when 'l' then up
      when 'd' then right
      end
    when 2
      case dir
      when 'r' then right
      when 'u' then up
      when 'l' then left
      when 'd' then down
      end
    when 3
      @ended = true
    end
  end

  def name
    ('a'..'p').to_a[(i * 4) + j]
  end

  private

  def up
    @point = [i - 1, j]
    @dir = 'u'
  end

  def down
    @point = [i + 1, j]
    @dir = 'd'
  end

  def right
    @point = [i, j + 1]
    @dir = 'r'
  end

  def left
    @point = [i, j - 1]
    @dir = 'l'
  end
end

def solve(tiles)
  map = tiles.split('/').map {|x| x.split('').map(&:to_i) }
  point = [0, 1]
  w = Walker.new(point)
  a = []
  while true
    break if w.ended?
    a << w.name
    w.move(map[w.i][w.j])
  end
  a.join
end

raise unless solve('0113/1201/2201/2100') == 'bcgfeabfjnoklpo'
raise unless solve("2110/2013/2210/0122") == "bcgh"
raise unless solve("2222/2130/2121/2002") == "bfg"
raise unless solve("0021/2212/2102/1220") == "baeimnoplhdcbfjkgfe"
raise unless solve("0213/1221/0220/1103") == "bfjnokgcbaefghlkjimn"
raise unless solve("3201/3120/3333/3333") == "bfghdcgk"
raise unless solve("3233/3233/3133/3333") == "bfjk"
raise unless solve("3333/3333/3333/3333") == "b"
raise unless solve("1212/1201/2123/2220") == "bfjkl"
raise unless solve("2212/3102/1002/2100") == "bfgcba"
raise unless solve("0023/2221/1102/0031") == "baeijnm"
raise unless solve("1121/3120/0212/1120") == "bcdhgfba"
raise unless solve("2202/3211/2120/1210") == "bfjklhgcd"
raise unless solve("3201/3211/1111/0100") == "bfjkonjie"
raise unless solve("0121/1120/1111/1211") == "bcdhgfbaefjkop"
raise unless solve("1212/1213/2103/0213") == "bfjkgfea"
raise unless solve("1121/2212/1323/3031") == "bcdhl"
raise unless solve("0030/1230/1121/0031") == "baefg"
raise unless solve("2223/1211/0002/1200") == "bfjimnokl"
raise unless solve("3210/0033/0201/0130") == "bfei"
raise unless solve("0213/2220/0021/3002") == "bfjim"
raise unless solve("2121/2112/1110/1010") == "bcdhlkgfba"
raise unless solve("0113/1003/2303/2220") == "bcgfj"
raise unless solve("2202/1110/1302/0313") == "bfgkj"
raise unless solve("1211/3202/2102/0222") == "bfjkgh"
raise unless solve("3113/0002/0112/1022") == "bcgfjko"
raise unless solve("1200/3000/0121/0121") == "bfe"
raise unless solve("2221/1122/1031/2200") == "bfgh"
raise unless solve("1202/0121/0222/1300") == "bfghlpo"
raise unless solve("0002/1012/1021/3300") == "baefbc"
raise unless solve("0211/1200/2220/2103") == "bfjnokghdc"

Mac + zshで音声リマインダ

動機

キーボードだけで操作できて、音声でリマインドしてくれる(画面切り替える必要が無い)簡単なリマインダが欲しかった。

実装

~/.zshrc

remind() { sleep `expr 60 \* $1`; say $2 -v Kyoko; }

と書いて、 source ~/.zshrc とすれば準備完了。あとは

remind 1 リマインドだよ

で1分後に「リマインドだよ」と音声で教えてくれる。