@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Rails が params をネストしてくれる仕組みは ActionController::ParamsWrapper が実現している

アレがどのように実現されてるのか、あとネストしたハッシュのキーにあたる文字列は単数形になるものなのか複数形になるものなのか、理解しておらず不思議がっていたら同僚が調べてくれた。復習がてらメモ。

結論

  • 一連の仕事は ActionController::ParamsWrapper がやっている
  • ネストされたハッシュの root key の名前は(おおざっぱにいうと)コントローラ名から切り出したモデル名の lower case になる。つまり(ほぼ)必ず singular (単数形)になると考えてよい。 参考コード1 参考コード2

以下、例。

コントローラとモデルの定義とルーティング

class User < ActiveRecord::Base
end
class UsersController < ApplicationController
end

Rails.application.routes.draw do
  resources :users
end

/users に POST リクエストで JSON を送る

$ curl -X POST \
     -H 'Content-Type: application/json' \
     -d '{"foo":"bar"}' \
     http://localhost:3000/users

Rails のログに出力されるパラメータはこんな感じになる

Parameters: {"foo"=>"bar", "user"=>{"foo"=>"bar"}}

UsersController から user が得られる過程はだいたいこんなコードになっている

model_name = UsersController.name.sub(/Controller$/, '').classify
#=> "User"
model_klass = model_name.safe_constantize
#=> User < Object
param_root = model_klass.to_s.demodulize.underscore
#=> "user"

GitHub Flavored Markdown の Task Lists の数を数える

小ねた。ちょうど今日必要にせまられたので。

そもそも目視で数えられないほど多くチェックリストを作るなという話ではあるけど、 TODO が全部で何個あってそのうち何個終わってるか知りたいときは Markdown をコピペしてファイルに保存し、 grep するのが手軽。

TODO が全部で何個あるか数える

$ grep -c -E '\[.\]' todos.md 
46

DONE な TODO が何個あるか数える

$ grep -c -E '\[x\]' todos.md 
20

未完了な TODO が何個あるか数える

$ grep -c -E '\[ \]' todos.md 
26

サンプルデータ

https://github.com/kyanny/test/issues/5

$ cat todos.md | head
* [x] Deleniti aut maiores nam ut ut.
* [ ] Molestias voluptatem eos deleniti quae accusamus voluptatum enim.
* [ ] Deleniti repellat illum eius dignissimos.
* [ ] Eum sit sed sed blanditiis nisi quo.
  * [ ] Pariatur ab id excepturi iure quaerat culpa.
* [ ] Repudiandae esse magni alias corrupti.
* [ ] Autem fuga dolorem vero reiciendis est repudiandae illum quia.
  * [x] Alias numquam magni et expedita odio enim soluta.
    * [x] Accusantium impedit necessitatibus vero neque aut.
* [ ] Magni officiis sunt quasi consequatur iusto velit et.

Book: Zero to One

ちょっと話題になっていたので読んだ。前半はなかなか面白かった。後半は息切れを感じた。

前書きを含め、リーンスタートアップへの痛烈な批判が目につくが、むしろ本書を読んで手法としてのリーンスタートアップはいいものだと再認識した。

本書が批判しているのはイデオロギーとしての(もしくは宗教としての)リーンスタートアップのほうだろう。「10倍の改善」に至らない既製品のコピーをいくら改善したってモノにならないじゃん、ということだ。


印象に残ってメモしたフレーズ

  • ゼロを一にする進歩を一言で表すとテクノロジー。コンピューターに限らず新しい取り組み方やより良い手法はすべてテクノロジー。
  • スマートフォンで生活が変わった気になっても、環境は変わっていない。
  • 新しい会社の一番の強みは新しい考え方
  • コモディティはだめ、独占が成功企業の条件だ
  • 人生が運に左右されると信じているなら、なぜ君は本書を読んでいるのだろう?
  • ここで売るとかありえませんよね
  • べき乗則
  • 競争は資本主義の対極にある
  • 企業文化は持つものじゃない。企業そのものが文化だ。
  • 時間はいちばん大切な資産なのに、ずっと一緒にいたいと思えない人たちのためにそれを使うのはおかしい。
  • 差別化されていないプロダクトでも、営業と販売が優れていれば独占を築くことはできる。逆のケースはない。
  • 強力な販売戦略の支援が必要
  • 人間が難しい問題を解決するのをコンピュータがどう助けられるか
  • 本当に社会のためになるのは、これまでと「違う」ものだ。

ゼロ・トゥ・ワン―君はゼロから何を生み出せるか

ゼロ・トゥ・ワン―君はゼロから何を生み出せるか

ゼロ・トゥ・ワン 君はゼロから何を生み出せるか

ゼロ・トゥ・ワン 君はゼロから何を生み出せるか

Backbone.sync で毎回パラメータを付与する with Rails

いつもよくわからなくなって混乱するので調べてまとめた。実験に使ったアプリ https://github.com/kyanny/backbone_sync_rails_app

フロントエンドを Backbone.js、バックエンドを Rails として、 fetch/save/destroy いずれの場合も必ず token というパラメータを付与したい場合、それぞれ以下のようになる。

fetch (id なし)

fetch にパラメータをつけたい場合は data: {token: 'abc'} の形でオプションを渡す。

user = new User
user.fetch
  data:
    token: 'abc'
GET http://localhost:3000/users?token=abc

Started GET "/users?token=abc" for 127.0.0.1 at 2014-12-08 22:51:31 +0900
Processing by UsersController#index as JSON
Parameters: {"token"=>"abc"}
""
Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms)
fetch (id あり)
user = new User id: 123
user.fetch
  data:
    token: 'abc'
GET http://localhost:3000/users/123?token=abc

Started GET "/users/123?token=abc" for 127.0.0.1 at 2014-12-08 22:51:32 +0900
Processing by UsersController#show as JSON
Parameters: {"token"=>"abc", "id"=>"123"}
""
Completed 200 OK in 2ms (Views: 0.4ms | ActiveRecord: 0.0ms)
save (id なし)

save の場合は model の attributes が JSON になった文字列がリクエストボディになるので save の第一引数で渡す(もしくは model.set してもいい)

user = new User
user.save
  token: 'abc'
POST http://localhost:3000/users

Started POST "/users" for 127.0.0.1 at 2014-12-08 22:51:33 +0900
Processing by UsersController#create as JSON
Parameters: {"token"=>"abc", "user"=>{"token"=>"abc"}}
"{\"token\":\"abc\"}"
Completed 201 Created in 2ms (Views: 0.5ms | ActiveRecord: 0.0ms)
save (id あり)
user = new User id: 123
user.save
  token: 'abc'
PUT http://localhost:3000/users/123

Started PUT "/users/123" for 127.0.0.1 at 2014-12-08 22:51:34 +0900
Processing by UsersController#update as JSON
Parameters: {"id"=>"123", "token"=>"abc", "user"=>{"id"=>"123", "token"=>"abc"}}
"{\"id\":123,\"token\":\"abc\"}"
Completed 200 OK in 1ms (Views: 0.1ms | ActiveRecord: 0.0ms)
destroy

destroy の場合は model の attributes は送られないので data: {token: 'abc'} の形でオプション渡しする必要がある。なおかつ processData: true をつけないと [object object] みたいな文字列がサーバーに送られてしまう。

user = new User id: 123
user.destroy
  data:
    token: 'abc'
  processData: true
DELETE http://localhost:3000/users/123

Started DELETE "/users/123" for 127.0.0.1 at 2014-12-08 22:51:34 +0900
Processing by UsersController#destroy as JSON
Parameters: {"token"=>"abc", "id"=>"123"}
"token=abc"
Completed 204 No Content in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms)

AWS の IOPS 課金でパケ死しかけた

クラウド破産 - Togetterまとめ

これより金額は一桁少ないけど、考えなしに AWS で大量の IO が発生するベンチマークを実行して請求額が跳ね上がった。次回の請求額が $231 もあって、思い当たる節があったので明細をみてみたら予想どおり SSD な EBS ボリュームに対する IOPS のコストがかさんでいた。

f:id:a666666:20141203232620p:plain

f:id:a666666:20141203232629p:plain

実行したベンチマークはこれ https://github.com/kyanny/bench_20141106 で、 MongoDB でコレクションからランダムに findOne するとき、コレクション内のドキュメント数によってパフォーマンスに差が出るのかどうかを確認したかった(インデックスを利用したクエリ)ちなみに結果は「大差なかった」。

知人に「EC2 インスタンスじゃ同一スペックでも同じハードウェアにはならないからベンチマーク取っても意味ないっしょ」と突っ込まれてなるほどと思ったけど後の祭り。短時間で発生する従量課金なので CloudWatch の Billing alarm が飛んできたとしても時すでに遅しだったと思うけど、 $10 とか低い金額にしかセットしてないのは良くないので段階的になるように alarm を増やすつもり。

先人の知恵から何も学ばなかったので高い授業料を払うはめになったけど、なにごとも一回失敗して痛い目みたほうが身につくと思っているので、これはこれで良い経験だった。でももしこれが一桁二桁違っていたらと想像して手が震えた。


そもそもなぜ月額定額の VPS ではなく従量課金の AWS でベンチマークなんてとろうと思ったかというと、ベンチマーク実行環境の再現性を考えてのことだった。

ハードウェア面で同一条件にならないという点を忘れていたので根底からロジックが破綻しているけど、ベンチマークは追試できることが重要だと考えていて、それにはベンチマークプログラムが公開されていることだけでなく、ベンチマーク実行環境と同じ環境を他の人が準備できることも重要だと思う。

「自分の MacBook Pro でやりました」とかだと、他の人が他のマシンで同じベンチマークを実行した数値と公平に比較できない。かといって「自分の個人契約している VPS でやりました」とかだと同一条件の環境を他の人が準備しづらい。 AWS ならインスタンスタイプもマシンイメージも同一の条件を用意しやすい。

追試できないので検証不可能なのと、追試できるけど誰も検証しないのとの間には大きな差がある。他の人がベンチマークをとって数値だけ見せてるのをみて、「その数値を信じる根拠は?」ともやもやを感じることがあるので、自分が数値を見せられる立場だったとき不信感が少なくなるようなやり方を考えて実践してみたらコンピューティングリソース(とお金)を無駄遣いしてしまった、というのが今回の顛末。

次からは DigitalOcean を使おうと思う。