はてなブログに
http://tompng.hatenablog.com/
はてなブログ開設しました ぽちっとな
RailsのN+1避けのものもう一つ作った
RailsでFoo.where(condition).n1_safeと付け加えるだけで簡単にN+1クエリを回避出来る奴
https://github.com/tompng/n1_safe
使い方
gem 'n1_safe', github: 'tompng/n1_safe'
@posts = Post.all.includes(:comments,ほげほげ)
みたくincludesする代わりに
@posts = Post.all.n1_safe
@post = Post.find(params[:id]).n1_safe
とつけ加えるだけでN+1が起こらなくなる。
@posts.each{|post| post.comments.each{|comment| comment.user.id comment.favs.count } }
SQLはこんな感じ
Comment Load (0.8ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" IN (1, 2, ... 19, 20)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (20, 16, ... 15, 4)
(0.5ms) SELECT COUNT(*) AS count_all, target_id AS target_id FROM "favs" WHERE "favs"."target_id" IN (49, 73, ... 55, 67) AND "favs"."target_type" = ? GROUP BY "favs"."target_id" [["target_type", "Comment"]]
↑可能ならgroup_by/countもやるよ 出来ない場合(has_many throughの場合など)はpreloadしてto_a.sizeで代用
前作ったsmart_jsonは依存関係を定義から読んで先にincludesする方針。
今回は呼ばれて必要になった時にあとからpreloadする方針。
n1_safeを呼んだルートとなるオブジェクトを覚えておいて、
関連モデルを呼び出した時とRelationを配列にする時に、それを起点にpreloadする。
・BasicObject便利
・ActiveRecord::Associations::Preloader便利
・バージョン違い辛い
ActiveRecord::Base#reflectionsが無くなってたりreflectionsのkeyがsymbolかstringか違ったり
RailsでN+1が出ないようにas_jsonぽくする奴を作った
smart_json: RailsでN+1が出ないas_jsonぽい奴作りました。
https://github.com/tompng/smart_json
ちょくちょく直しながら作ってます。んで、実践投入しようかなと思ってるので記事書いとこうと。
smart_json?
gem 'smart_json', github: 'tompng/smart_json'
blogs.as_smart_json(posts: [:タイトル日付のみ, author: :詳細, comments: {user: :名前だけ}])
と指定してjsonを作れる、そして必要なincludesを自動でやってくれるのでN+1問題も起きない(はず)
smart_jsonが解決する問題:その1
posts.as_json(include: {comments: {include: :user}})
とかするとN+1クエリが出る、かといって
posts.includes(comments: :user).as_json(include: {comments: {include: :user}})
とするのはだるい。Don't repeat yourselfだくそ野郎
smart_jsonを使うと...
posts.as_smart_json(comments: :user)
smart_jsonが解決する問題:その2
as_jsonでonlyやmethodsに指定する内容は数通りしかないので、そのままだと
user.as_json(only: [:id, :name])
comment.as_json(only: [:id, :text], include: {user: {only: [:id, :name]}})
posts.as_json(include: {comments: {only: [:id, :text]}})
blogs.as_json(include: {owner: {only: ...}, posts: {include: {author: {only: ...}, comments: {only: ...}}}})
と重複だらけになってひどいしN+1対策でさらに長くなる。
smart_jsonでスタイルを定義しておけば...
class User smart_json_style(:default){as_json only: [:id, :name]} end class Comment smart_json_style(:default){as_json only: [:id, :text]} smart_json_style(:詳細, :user) end class Post smart_json_style(:簡易){{title: title, body: body[0..30]}} smart_json_style(:コメントなど含む, :簡易, :author, comments: :詳細) end
user.as_smart_json
comment.as_smart_json(:詳細)
posts.as_smart_json(:comments)
blogs.as_smart_json(:owner, posts: :コメントなど含む)
とすっきり書ける。これまた依存関係全部includesしてくれる。
誰か実験台になってくれちょ
(あと似たようなのが既にあれば教えてほしい)
将棋倶楽部24勝手にUIパッチ
将棋倶楽部24の対戦画面のUIをちょっと派手にするパッチのようなものを作りました。
1〜2年くらい前に。データ無くさないようにとgithubに上げた次第。
https://github.com/tompng/shogipatch24
将棋倶楽部24のUIがこんな感じに変わります。
参考動画
http://www.nicovideo.jp/watch/sm19784620
どんな機能があるの?
基本的にエフェクトがついただけです。
駒移動、定跡、成、王手、囲いとか。
使い方
1. dojoXXX.jarを、どこからか入手したdojo***.jar(***はバージョン番号)に置き換える
2. build.shでコンパイル
3. OsakaDojo.jar/TokyoDojo.jarをダブルクリックすると、パッチが当たった状態で起動します。
カスタマイズしたいなら
res/の画像と音を入れ替える
自分でコード書く
うまく動かないとき、使い方がわからないとき
`whoami`さんに聞きましょう。きっと不具合を修正してpullrequest送ってくれるはずです。
Rubyな日々
最近あまりにブログを書いてないのでRubyネタを2つほど
強い.zero? と Lisp in Ruby
強い.zero?
https://gist.github.com/tompng/5031911
RubyにあるFixnum#zero?メソッドを強くしてみました。
出来る事
.zero?以外に.one? .two?とかが使えます。
30.thirty? 1000.thousand? -102.5.minusonehundredtwopointfive?
0 1 2...の代わりにzero one two...を使えます
ten.times do |i| print "----" if i.five? p i*threepointonefour end
コード中の数値を全て英語表記に変えれちゃいます。誰得
仕組み
method_missingメソッドを定義しておくと、
存在しないメソッドを呼んだ時にゴニョゴニョできます
def method_missing name,*args if name.to_s.match /say_(.+)/ print "hello #{$1}!\n" else super end end say_world => hello world! say_goodbye => hello goodbye!
Lisp in Ruby
https://github.com/tompng/rubyhogelisp
(hoge (piyo (fuga 3),(foo 4,5)),(bar 5))
このLispっぽい表記がRubyだと構文エラーにならない。
じゃあいっそLisp動かしちゃおう、と思って。
結果
Lisp do (car (cons (cons 1,(list 2,3,4)),5)) end => (1, 2, 3, 4) Lisp do (progn\ (define (fact :n), (ifelse (eq :n,0), 1,(mult :n,(fact (sub :n,1))))), (fact 5) ) end => 120
Rubyのいろんなgemの機能も一応使えます
require 'sinatra' Lisp do (let :count,0, (call (get '/'), (progn\ (set :count,(add :count,1)), (set :cntstr,(send :count,(to_s))), (call (system 'say',:cntstr)), (add (send (call params),(to_s)),:cntstr) ) ) ) end => sinatraが動く!
ScreenX TV
前回のあのScreenXが進化してWEBサービスScreenX TVになりました。
http://screenx.tv/
Ruby on Rails + Node.jsの合わせ技使ってます。
まだ開発中です。
コーディング風景をリアルタイムでWeb配信する素敵ツール『ScreenX』
結構前に作った、ターミナル画面をリアルタイムで配信するツールを公開しました。
GitHub:tompng/screenx
チャット付きです。
セットアップ
RackHubを使う場合はこちらも参考に
https://gist.github.com/3547668
ビルド
$ git clone https://github.com/tompng/screenx
$ cd screenx
$ ./build.sh
サーバー起動
$ cd classes $ nohup java ScreenX &
配信開始
$ screen -x
これで配信するスクリーンが開きます。
配信URLは http://*****:8080/screenx.html
使うポートは設定で変更できます。
怪しくも素敵な隠れ機能 Web Login
httpフォルダを開くと、3つのhtmlファイルがあります。
- screenx.html 配信用。チャット付き。
- sxlogin.html 配信する時用のログイン。チャット見れる。ウインドウ幅固定
- login.html 普通にログインして作業する用。ウインドウ幅可変。
Login・・・だと・・・
なんと、ソースコードを確認した上で自己責任で次の事をすると、Webからログインする機能が使えてしまいます!
1. classes/screenx.conf の設定を変え、サーバーを再起動
EnableLogin | httpsでのログインを許可します。HttpsPort,KeyStoreFile,KeyStorePasswordも設定してください |
EnableHttpLogin | httpでもログインできるようにします。ログインパスワード以外はPlainTextです。危険度UP |
EnableCometLogin | Comet(WebSocketが使えない環境での代替策)でのログインを許可します。危険度さらにUP |
LoginPassword | チャレンジコード風の認証に使います。 |
DocumentRoot | ここを空にする場合、httpフォルダ内のファイルをお使いのWebサーバ(Apache等)のディレクトリにコピーしてください |
2. http/sxconfig.js を編集
ポートを変えたりhttpsを使う場合に書き換えてください。
また、WebSocketの使えない環境で動かす場合はforceCometをtrueにしてください。
アーキテクチャ
サーバーでUNIXのscreenコマンドをexecしてます。
そのscreenが吐く文字列(VT100エスケープシーケンス)をWebSocketで送っているだけ。
WebSocketが無いブラウザでは代わりにCometが使われます
そして、クライアント側ではjavascriptで書いた端末エミュレータがそれを解釈して表示しています。
※screenコマンドが吐くエスケープシーケンスは種類が少ないので、
端末エミュレータはそれだけに絞って実装しました。楽だし確実。
ちなみにscreenの代わりにbashをexecした場合、emacsの表示は結構崩れました。
ちょっといじったら問題無く使えるようになりました。(2012 9/3)
まとめ。
名前の由来はscreenコマンドを-x引数で起動するからScreenXです。
NHKのProjectXみたいな語感が良いね。
では、リスクを承知の上で素敵ングなTerminal Broadcastingをお楽しみ下さい。