表題のようなバグに遭遇し、結構苦労したのでメモです。
<div class="parent">
<select>
<option>1</option>
<option>2</option>
</select>
</div>
となっている場合に、jQueryで、
$(".parent").hide()
$(".parent").show()
していると、2回目以降で表示が変更されない場合がありました。 結構謎な現象でしたが、 http://tachesimazzoca.blogspot.jp/2011/12/android-mobile-safari-select.html を参考に、
$(".parent").hide() #=> $(".parent").attr("style","display:none")
$(".parent").show() #=> $(".parent").attr("style","display:block")
と変更することで動きました。 なぜこれで動くのかは不明です。
上記の設定をし、animationで画面を表示したのちスライドインで表示していましたが、結局同じ問題が出てきたので、animationを使わずスライドインさせない事で問題は解決。
//$(.parent).attr('style', 'display;block; right:400px;').animate('right:0px', 550);
=> $(.parent).attr('style','display:block;');
mobile_filterの処理を飛ばすのはSoftbankとVodaphoneのみになっていたので、IphoneとAndroidを追記する。 config/initialize/jpmobile.rb というファイルを新規作成して、下記のコードでオーバーライドする。
-- coding: utf-8 --
# module Jpmobile # =文字コードフィルタモジュール。 module Filter # Shift_JISとUnicodeのフィルタ(NKFを使用) class Sjis < Base # to_internalを適用するべきかどうかを返す。 def apply_incoming?(controller) # Vodafone 3G/Softbank(Shift-JISにすると絵文字で不具合が生じる)以外の # 携帯電話の場合に適用する。 # 20120510 kosaki add Iphone & Android mobile = controller.request.mobile mobile && !(mobile.instance_of?(Jpmobile::Mobile::Vodafone)||mobile.instance_of?(Jpmobile::Mobile::Softbank)||mobile.instance_of?(Jpmobile::Mobile::Iphone)||mobile.instance_of?(Jpmobile::Mobile::Android)) end end end end
fontfaceでアイコンを使っているけれど、さらに一歩進んで、枠と内容に分けて組み合わせるアイディアを実現化しているフォント。 素晴らしい。
rubyと違って、coffeescript(javascript)だと色々false判定される場合があったのでメモしておきます。
if val then "TRUE" else "FALSE"
| val | result |
|---|---|
| undefined | FALSE |
| undefined? | FALSE |
| null | FALSE |
| null? | FALSE |
| false | FALSE |
| false? | TRUE |
| 0 | FALSE |
| 0? | TRUE |
| -1 | TRUE |
| -1? | TRUE |
| NaN | FALSE |
| NaN? | TRUE |
| ”” | FALSE |
| ””? | TRUE |
以上です。?関係は、 a? が、
typeof a !== "undefined" && a !== null;
なので、当然かもしれませんが。
iPad版のView作ってくれという依頼がきたので、responsiveなcss入れたりして色々やっていました。
日付系の動作についてまとまっているところがなかったので、まとめておきます。 基本的には、iPad版のSafariの方がバグっぽいです。
| type | iPad Safari(iOS5.0.1) | mac Safafi(5.1.3) | |||
|---|---|---|---|---|---|
| datetime | local時間から開始、stepは効かない | UTC時間から開始、stepもちゃんと効く | |||
| datetime-local | local時間から開始、stepは効かない | local時間から開始、stepもちゃんと効く | time/date | local時間から開始、stepは効かない | local時間から開始、stepもちゃんと効く |
以上です。
嵌ったので、メモおよび共有しておきます。 嵌ったコードは下記です。
hoge = Backbone.View.extend
initialize:(opts={})
@options = opts
一見何も問題なさそうなんですが、Backbone.Viewが内部的に@optionsを処理していて、2回目以降のrenderでdelegateEventsがbindしないということになってしまいました。
しかも、よくdocを読むと、
constructor / initializenew View([options])
When creating a new View, the options you pass are attached to the view as this.options, for future reference.
There are several special options that, if passed, will be attached directly to the view: model, collection, el, id, className, tagName and attributes.
If the view defines an initialize function, it will be called when the view is first created.
If you'd like to create a view that references an element already in the DOM, pass in the element as an option: new View({el: existingElement})
と、書いており、@optionsは標準で提供されているようですね。
つまり、初期化のときに代入したオプションは、@optionsで無条件で取れるということでした。嵌ってしまったorz
下記の記事は、完璧に誤解してました。 同じ名前で、別のclusterってのがあるようでした。
本家に取り込まれている(http://nodejs.org/api/cluster.html)と、(https://github.com/LearnBoost/cluster) は別物でした。
node.jsを運用に載せる際に、webサーバーをどうしようかなと思っていましたが、 遅ればせながら、clusterが本家に取り込まれていることを知りました。
http://nodejs.org/api/cluster.html
ということで、今後の継続的な開発は全く心配無し。 内容的にも、ダウンタイムゼロでの再起動など、やりたいことを十分満たしていました。
https://github.com/LearnBoost/cluster
十分すぎるので、しばらくこいつでテストしてみようと思います。
クライアントサイドjsでのi18nと言えば、様々なツールがありますが、 シンプルに自分でも実装できるかなと思い、運用方法も含めて自分たちにあった方法を考えてみました。
基本的には、window.i18nという大きなObjectを作成して、keyにi18nのkey+localeを、valueに翻訳された値を入れておく
後は、適当にsyntax sugar用の関数を用意してあげる
普通の翻訳ファイルでは、翻訳者が異なることを想定し、言語毎にファイルを作成して運用することが多い。 そのため、トップレベルで言語が分かれるObjectになる。
i18n =
ja:
users:
name: "名前"
en:
users:
name: "name"
社内ではこの形式で弊社でも運用しているが、 各言語毎にファイルを作るため、言語ファイルが大きくなってくると、 各言語毎に翻訳項目の抜け漏れがないか調べにくくなってきてしまっていた。
そのため、script等を作成してチェックしていたが、なかなか億劫な作業でもある。
そこで、今回は思い切って標準的なトップレベルでの言語切り分けから、 下記のような、最末端での言語切替のObjectで運用してみようと考えた。
i18n =
users:
name:
ja: "名前"
en: "name"
メリットとしては、属性毎に翻訳していくので、自然な構造なので、抜け漏れなどが分かりやすく、システム化もしやすいと判断した。
次に、このObjectをどのように作って行くか考えた。 最終的には、jsonからjsのObjectにするのだが、jsonを手で書くのが面倒なので、 思い切ってnumbers=csv等で管理するのはどうかなと思いついた。
例としてはこんな感じ
| key | ja | en |
|---|---|---|
| users.name | 名前 | name |
| users.email | メールアドレス |
で、このcsvをjsonに変換して、そいつをjsとして読み込んでしまおうという作戦にすることに。
csvにすることで、ささっと手で直すこともできるし、 mergeとかが面倒であれば、GoogleSpreadSheet使っても良いし、Editorとしてはなかなか良い感じがする。
次に、csvからjsに変換するscriptを書いた。
まずは、csvからjsonに変換するコードをささっとruby(1.9.3)で。
csv2json
1 #!/usr/bin/env ruby
2
3 require 'csv'
4 require 'json'
5
6 reader = CSV.open("./js/i18n.csv","r")
7 header = reader.take(1)[0]
8
9 i2s = header.each.with_index.inject({}){|h,(attr,i)| h[i.to_s]=attr.strip;h }
10 i18n = {}
11
12 class Hash
13 def nset(keys=[],val)
14 k = keys.shift
15 keys.empty? ? self[k] = val : (self[k]||={}; self[k].nset(keys,val))
16 end
17 end
18
19 reader.each do |row|
20 keys = []
21 val = {}
22 row.each.with_index do |c,i|
23 if (attr = i2s[i.to_s]) == "key"
24 keys = c.split(".")
25 else
26 case c
27 when "BLANK"; val[attr] = ""
28 when nil; ""
29 else; val[attr] = c
30 end
31 end
32 end
33 i18n.nset(keys,val)
34 end
35
36 puts i18n.to_json
37
で、こいつを使って、csv2jsをさくっと作成
csv2js
1 #!/bin/bash
2
3 echo -n "window.i18n="
4 ./script/csv2json

あとは、こいつを所定のファイルに吐き出してあげればOKです。 ここまでで、numbersでcsvを作って、jsのObjectにするまでができました。
で、最後にRailsっぽく、tというメソッドを作りました。 なので、t(“users.name”)とかで呼べます。
1 $ ->
2 #### t
3 # keyとlocaleを設定して翻訳Objectから値を持ってくる
4 # localeに"obj"が渡されたときは、objを表示する
5 # * 翻訳があるもの #=> 設定した文字列を表示
6 # * 翻訳していないものやそもそも存在していないもの #=> keyの最後の部分を表示
7 window.t =(key,locale)->
8 try
9 locale ||= app.currentUser().locale
10 if locale=="obj"
11 val = _.nget window.i18n, key
12 else
13 val = _.nget window.i18n, "#{key}.#{locale}"
14 if val?
15 return val
16 else
17 return key.split(".").last()
18 catch e
19 console.log e
20 return key.split(".").last()
少し拡張して、下記のような仕様にしています。 t(“user.name”) #=> “名前” t(“user.name”,”en”) #=> “name” t(“user.name”,”ja”) #=> “名前” t(“user.name”,”??”) #=> “name”(keyの最後) t(“user.nam”,”ja”) #=> “nam”(keyの最後) t(“user.name”,”obj”) #=> {en: “name”, ja: “名前”}
これで、あとはjsから使えば楽しく使えそうです。 Objectの構造も言語を最後にしているので、
t("user.name","obj") #=> {en: "name", ja: "名前"}
のようなこともできるようになっています。
numbers -> csv -> jsのObject のフローを運用を考えながら作りました。 numbersで見ると翻訳の抜け漏れも分かりやすかったり、ソートできたりと便利な上に、 yamlを翻訳者に書いてもらう必要もなくなりました。
jsだとシンプルにこんなツールが作れるので楽しいですね。
websocketをIEでも使えるらしいjs
前回のポストの値で大丈夫かなと色々調べてみると、mysqltuner.plというものがあることを発見。 早速使ってみました。
とりあえずインストールして回してみました。
$ wget https://raw.github.com/rackerhacker/MySQLTuner-perl/master/mysqltuner.pl
$ chmod +x mysqltuner.pl
$ ./mysqltuner.pl
$ ./mysqltuner.pl
省略
-------- Recommendations -----------------------------------------------------
General recommendations:
Enable the slow query log to troubleshoot bad queries
When making adjustments, make tmp_table_size/max_heap_table_size equal
Reduce your SELECT DISTINCT queries without LIMIT clauses
Increase table_cache gradually to avoid file descriptor limits
Variables to adjust:
query_cache_size (>= 8M)
tmp_table_size (> 32M)
max_heap_table_size (> 16M)
thread_cache_size (> 900)
table_cache (> 900)
innodb_buffer_pool_size (>= 2G)
とオススメ値が色々出ました。 これは楽チン
ということで、設定を下記に変更しておきました。
[mysqld]
max_connections=300
query_cache_size=32M
tmp_table_size=1024M
max_heap_table_size=1024M
thread_cache_size=1200
table_cache=1200
innodb_buffer_pool_size=2G