jQuery Mobileでlistviewに動的にエレメントを追加する
jQuery Mobileってあるじゃないですか。
あれってHTMLのdata属性を見て、勝手に要素に色々属性つけて見栄え良くするんですけど、$(jQuery).append()とかで属性を付与すると、付与した属性には当然そういった処理はやってくれないんで、追加した属性だけみすぼらしくなります。
たとえば
みたいのがあったとして、<section data-role="page" data-iscroll="enable" id="list">
<div class="content" data-role="content" data-iscroll="scroller" id="scroll_list">
<ul data-role="listview">
</ul>
</div>
</section>
こいつに
とかってやっても、当然$page = $("#list");
$list = $page.find(".content ul");
$list.append("<li>あああああ</li>");
が足されるだけで、自動的に<li>
になってくれるわけではありません。<li class="ui-btn ui-btn-icon-right ui-li-has-arrow ui-li ui-li-has-thumb ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="div" data-icon="arrow-r" data-iconpos="right" data-theme="c">
で、listviewの場合は$listに対して.listview()を呼び出せば良いわけなんですが、
$page = $("#list");
$list = $page.find(".content ul");
$list.append("<li>あああああ</li>");
$list.listview();
これが何故か上手くいかない。
何でかと思ってjQueryMobileのドキュメントを読んでたら
スクリプトからリストにアイテムを追加した後は refresh() メソッドを呼んで明示的にスタイルを更新してやる必要があります。
orz
これってもしかして1.0からなのかしら?
これで解決!$page = $("#list");
$list = $page.find(".content ul");
$list.append("<li>あああああ</li>");
$list.listview("refresh");
macでemacs -nwを使うとriskyと言われる
mac osxには標準でnw版のemacs 22が入っているのだが、init.elに23用のプラグインが入ってるとエラーになります。
こんなかんじで
signal(error ("Unknown keyword :risky"))
error("Unknown keyword %s" :risky)
custom-handle-keyword(package-load-list :risky t custom-variable)
Emacs.appに引数を付けて呼び出せば新しいバージョンを呼び出せます。
しかしこれは間抜けだなあ。と思い、解決策を考えました。
which emacsでデフォルトemacsの場所をさがし、どこかにバイナリファイルを移動、その後ソースをダウンロードしてコンパイルすると新しいemacsがインストールされ、nwでもちゃんと開くようになります。
上書きはしないようなので、移動しないとダメです。
MySQLでrootなのにgrantコマンドが実行できない場合の対処法
rootでログインしてユーザーを増やそうと思ったら
と怒られた。mysql> grant all on *.* to "myuser"@"192.168.0.0/255.255.255.0";
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
調べてみたら色々対処法があるみたいだが、とりあえずエラーログを見てみると
120801 9:43:15 [ERROR] Missing system table mysql.proxies_priv; please run mysql_upgrade to create it
言われた通りmysql_upgradeを実行すると
それ以外にも幾つかテーブルが足りなかったようで、作ってくれた。[root@localhost ~]# mysql_upgrade
Looking for 'mysql' as: mysql
Looking for 'mysqlcheck' as: mysqlcheck
Running 'mysqlcheck with default connection arguments
Running 'mysqlcheck with default connection arguments
mysql.columns_priv OK
mysql.db OK
mysql.func OK
mysql.general_log OK
mysql.help_category
error : Table upgrade required. Please do "REPAIR TABLE `help_category`" or dump/reload to fix it!
mysql.help_keyword
error : Table upgrade required. Please do "REPAIR TABLE `help_keyword`" or dump/reload to fix it!
mysql.help_relation OK
mysql.help_topic
error : Table upgrade required. Please do "REPAIR TABLE `help_topic`" or dump/reload to fix it!
mysql.host OK
mysql.proc
error : Table upgrade required. Please do "REPAIR TABLE `proc`" or dump/reload to fix it!
mysql.procs_priv OK
mysql.servers OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
mysql.time_zone_name
error : Table upgrade required. Please do "REPAIR TABLE `time_zone_name`" or dump/reload to fix it!
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OKRepairing tables
mysql.help_category OK
mysql.help_keyword OK
mysql.help_topic OK
mysql.proc OK
mysql.time_zone_name OK
Running 'mysql_fix_privilege_tables'...
OK
再度grantしてみる
今度はOKmysql> grant all on *.* to "myuser"@"192.168.0.0/255.255.255.0";
Query OK, 0 rows affected (0.00 sec)
入れたrpmが足りなかったのか、mysql_install_dbがおかしかったのか管理テーブルが足りなかったのが原因のようだ。
Facebook認証時、モバイル用ページを表示する
Oauth認証する際、APIに送るリクエストの末尾にdisplay="touch"をつけるとモバイル用のページが表示される。
通常のWEBページだったらdisplay=pageをつける(displayを付けないとこのページが採用されるようだ)
こんなかんじで
エラーメッセージによれば、他にpopup, wapがあるようだ
Parameters: {"error"=>"invalid_request", "error_description"=>"Unsupported display: 'touch1'. Supported displays: popup, page, wap, touch"
facebook_oauthを使ってる場合、displayパラメタを付与できる作りになってないので、モンキーパッチを当てました。
facebook_oauth/lib/facebook_oauth/client.rb
15 15 client.auth_code.authorize_url(
16 16 :client_id => @application_id,
17 17 :redirect_uri => options[:callback] || @callback,
18 - :scope => options[:scope]
18 + :scope => options[:scope],
19 + :display => options[:display] || "page"
19 20 )
20 21 end
呼び出し側も修正
redirect_to client.authorize_url(:scope => 'emailとか', :display => "touch")
たぶんmoduleをオーバーライドするのが正解なんだけど、誰か方法教えてください><
FacebookのOAuth認証使ったアプリのテストを書く
facebook_oauth+Oauth2の場合
多分koalaでも基本一緒
Facebookへのトークン取得と自分の基本情報をfacebook_oauthから取得するようなプログラムのテストを書く場合
の計2回Facebook APIを叩く必要がある。1.トークン取得
2.情報取得
まじめにやるならfoge_controller_test.rbに
を追加して、FB側からのコールバック処理にrequire 'uri'
require 'net/http'
としてやれば動くはず。get :callback, { :code => "自分が使ってるホントのトークン"}
ただ、アクセストークンは勿論固定ではないし、これだと自分自身のデータしか使えないのでユーザーごとに処理を変えるというようなことができない。
そこで、APIへのアクセスをダミー化してやる必要がある。
ダミー化するためにfakewebを使う
Gemfile
gem 'fakeweb'
テストコントローラーでfakewebを使う
hoge_controller_test.rb
require 'fakeweb'
先述の通りfacebook APIへの接続はトークン取得と情報取得2回発生するする。
なのでテストファイルには、まず1回目のアクセス用
https://graph.facebook.com/oauth/access_tokenがアクセストークン取得用URLだが、前方一致で/oauthまででおkFakeWeb.register_uri(:any, %r|https://graph\.facebook\.com/oauth|,
{:body => "access_token=12345", :status => ["200","OK"]}
)
2回目のアクセス(データ取ってくる用)
https://graph.facebook.com/meがデータ取得用APIなので、トークン取得用と2回に分けて記述する必要がある。FakeWeb.register_uri(:any, %r|https://graph\.facebook\.com/me|,
{:body => JSON.generate(:id => 11111111, :name=>'ほげほげ'),
:status => ["200","OK"],
:content_type => "application/json"}
)
ハマったのはパラメータの方で、facebookのAPIは、リクエストに対してjson形式の値をbodyに入れて返すのだが、OAuth2がレスポンスヘッダに応じて処理を変えているため、明示的に:content_typeを指定してあげないといけない。
今回はfacebook_oauthを使ったが、たぶんこのへんはベースにOAuth2を使ってるkoalaでも一緒だと思う。
というか最近はfacebook_oauthは古くてkoalaが全盛だし、しかもさんざん調べてfakeweb使ったのにwebmockのほうがトレンドとかrubyってホント移り変わりが早い。
あとコントローラーに処理バリバリ書いてたのに、普通はモデルに書くもんだとかさ、どっかにそういうの書いておいてよマジで。
ruby-electricのend補完が効かない件
最近会社からmacを支給されたので、windowsからmacに鞍替えしました。
Windows(しかもXP)の頃はリッチなGUIでいたせりつくせりなAptanaでコーディングしていたわけですが、Macでも当然Aptana使おうと思ったら、なんかクールなギーグはEmacs!みたいな風潮があるらしく、別にクールでもギーグでもないんですが、転職活動の際のエディタ採用対策に、Emacsを使うことにした。
で、いろいろ機能拡張を入れてて、今はRailsで開発してるので、ruby-electricを入れたんだけど、説明にあるような、def 〜 end自動補完が動かない。
どうもこことか見てると、最新のバージョンで関数が足りないらしい。
困ったらstackoverflowということで、調べてみたらそのものスバリな記事が。
ということで、落としてきたruby-electric.elに
(defun ruby-insert-end ()
"Insert \"end\" at point and reindent current line."
(interactive)
(insert "end")
(ruby-indent-line t)
(end-of-line))
を追加してバイトコンパイルしたら無事に使えるようになりました。
MySQLでDate関数同士を比較するときの注意
MySQLには日付の計算を行う関数がいくつかあって、例えば当日は
mysql> SELECT NOW();
- ---------------------+
NOW()
- ---------------------+
2012-04-23 16:26:11
- ---------------------+
1 row in set (0.00 sec)
前日は
mysql> SELECT NOW() - interval 1 day;
- ------------------------+
NOW() - interval 1 day
- ------------------------+
2012-04-22 16:28:17
- ------------------------+
1 row in set (0.00 sec)
で、これを日付だけ取り出したい場合、Date()を使う
mysql> SELECT date(NOW() - interval 1 day);
- ------------------------------+
date(NOW() - interval 1 day)
- ------------------------------+
2012-04-22
- ------------------------------+
1 row in set (0.00 sec)
単体で動かしているならこれで問題ないんだけど、Date()同士の引き算の結果がおかしくて軽くハマったので備忘録
まず同一月の引き算
mysql> SELECT DATE(NOW());
- -------------+
DATE(NOW())
- -------------+
2012-04-23
- -------------+
1 row in set (0.00 sec);
mysql> SELECT DATE(NOW() - INTERVAL 1 DAY);
- ------------------------------+
DATE(NOW() - INTERVAL 1 DAY)
- ------------------------------+
2012-04-22
- ------------------------------+
1 row in set (0.00 sec);
mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY);
- --------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 1 DAY)
- --------------------------------------------+
1
- --------------------------------------------+
1 row in set (0.00 sec)
同月同士なら全く問題なく計算できる。これが月をまたぐと全くおかしくなる。
!?mysql> SELECT DATE(NOW());
- -------------+
DATE(NOW())
- -------------+
2012-04-23
- -------------+
1 row in set (0.00 sec)
mysql> SELECT DATE(NOW() - INTERVAL 23 DAY);
- -------------------------------+
DATE(NOW() - INTERVAL 23 DAY)
- -------------------------------+
2012-03-31
- -------------------------------+
1 row in set (0.00 sec)
mysql> SELECT DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY);
- ---------------------------------------------+
DATE(NOW()) - DATE(NOW() - INTERVAL 23 DAY)
- ---------------------------------------------+
92
- ---------------------------------------------+
1 row in set (0.01 sec)
どうも日付同士の演算をする場合、Date()だと年を365日、月を30 or 31 or 29として計算し直すのではなく、単純に年、月を10進数で+1桁としているようだ。
だからひと月前は30日ではなく、100、年は1000が足されたような格好になる。
なので日付どうしの計算を行う場合は、ちゃんとTO_DAYSを使いましょう。
mysql> SELECT TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY);
- ---------------------------------------------------+
TO_DAYS(NOW()) - TO_DAYS(NOW() - INTERVAL 23 DAY)
- ---------------------------------------------------+
23
- ---------------------------------------------------+
1 row in set (0.00 sec)
もしくはDATEDIFF
mysql> SELECT DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY));
- ------------------------------------------------------+
DATEDIFF(DATE(NOW()), DATE(NOW() - INTERVAL 23 DAY))
- ------------------------------------------------------+
23
- ------------------------------------------------------+
1 row in set (0.00 sec)
使用頻度はどっちが高いんだろう。