Facebookで海外でお世話になった方の訃報がわかりました

大学の頃にインターネットが一般に広まっていったころ、私もMacを買って毎日ネットサーフィンやチャットを楽しんでいました。

当時AOLというプロバイダがメジャーで、私もそれを使っていました。
その中にはウェブメールやチャットルームなどがあって、
海外の人たちと話がしたいと思った私は、つたない英語で彼らと話をしていました。
その中で一人のアメリカ人の男性とよくメールやチャットをするようになりました。

彼は当時50才くらいで教師をしていたことがあるらしく、
またベトナム戦争で負傷し、日本に運ばれてそこで日本人に世話になったといっていました。

だから、私のつたない英語や幼稚な会話につきあってくれたんだと思います。

半年ぐらいそのような日々が続いたある日、彼が「家に来い」というのです。
そんなわけでいわゆる学生のホームステイという形でなく、
インターネットで知り合った、しかも海外の人に会いに行くという、
今でこそよくあるのかもしれないことを危険も顧みず実行したのでした。

彼はRhode Islandというニューヨークとカナダの間にあり、ボストンに隣接した小さな州に住んでいました。

安いチケットだったので、ボストンの空港に着いたのはちょうど日をまたぐような時間でしたが、彼が車で迎えに来てくれる予定でした。

ところが彼がおらず、「あー。こういうこともあるかな」とあきらめて宿を探そうとしていたとき、
アナウンスで私の名前が流れ、無事に彼に会えたのでした。渋滞につかまっていたのだそうです。

ここから3週間という長くも短くもある時間を彼の家ですごしました。
料理を作ったり、馬の世話をしたり、犬や猫と遊んだり。
田舎のカジノに行ったり、ボストンまで行ってすしを食べたり。

この出来事がなければ、私はインターネットに関する仕事に付いていなかったでしょう。
ボトルに手紙を詰め、太平洋をまたいで流れ着いたメッセージが届く。
若き日の私はそんなロマンを 興奮とともにインターネットの力を体験したのでした。

 

 

私は大学を卒業し、就職をし、実家を出ていったころ、
AOLが使えなくなったのもあり、
通常のメールが届いていないのか、返信が無かっただけなのか、
彼と連絡が取れなくなりました。

気にはなっていたものの、 連絡する方法も思い当たらず、
彼のことを忘れる時間も増えていき、結局それ以来、彼と連絡が取れないでいました。

Facebookでもしかしたらと思い彼の名を検索にかけてみましたが、
一度も彼らしき人を見つけることができませんでした。

今日も同様にやはり彼らしき人を見つけることはできなかったのですが、
彼の住んでいるRhode Islandとともに検索をしたとき、
見覚えのある名前が目に留まりました。彼の姪です。

私が滞在中に一度だけ30分くらいの時間でしたがあったことのある人でした。
検索結果が表示されるまで彼女の名前は忘れていました。

間違いないと思ってメッセージを投げ、その直後ある彼女の記事が目に留まったのです。

彼が亡くなったという内容の記事でした。それも数日前に。
ショックでした。

 

 

彼と連絡をとることはもう二度とできなくなりました。話すことも会うことも。
後悔がのこります。もっと真剣に探して入ればよかった。

それでも彼の死を私は知ることができました。
滞在中、彼の父母のお墓に一緒にお参りにいったことを思い出します。

いつか彼のお墓に行き、もう一度お礼を言おうと、そう誓います。

Ruby on Rails 3.2: CSVをアップロードしてActiveRecordにつっこむ

ユーザーにエクセルで出力したCSVをあげさせて、ActiveRecord経由でDBにデータを格納したいという用途は結構ある気がしますが、なかなか情報がないのでやってみた記録をします。

アップロードしたCSVをDBのデータとして使用するのには3つのハードルがあります。

  • CSVをどのようにしてパースするか
  • パースしたCSVからどのようにデータを格納するか
  • エンコーディングの問題

まずCSVをパースするのにはCSVのライブラリを用います。

require ‘csv’
source = params[:csv].read
parsed = CSV.parse(source)

とします。これでparsedに配列(行)の配列(列)がはいれます。

これをループして必要なデータを取り出しますが、

parsed.each do | row |
#row
end

データを取り出したらあとは普通に文字列として扱えますのでActiveRecordを介してDBに格納すればOKです。

しかし、文字コードの問題が残っています。

一番最初のCSVをアップロードした時点でKconvというライブラリを用いてエンコーディングすることで対応しました。

require ‘csv’
require ‘kconv’
source = params[:csv].read
source = Kconv.toutf8(source)
parsed = CSV.parse(source)

また、parsedに対しては配列の数がただしいかどうか、正しい位置に期待通りの値が入っているか、などの細かなチェックは必要です。

visualize.jqeury.jsはjquery ver.1.8で動かない(2012.9現在)

グラフを表示するjavascriptライブラリのvisualize.jqeuryを試してみました。
が、動かない。

エラーも無く、静かに枠だけが表示されます。

サンプルは表示されるのになぜ?と試行錯誤していると、
jqeuryのバージョンが1.8だと動かないようです。

どうやらjqueryのfilterメソッドに仕様変更があったようで、
visualize.jquery.js内でfilter(‘ ‘)とデフォルトで呼び出している箇所があります。
これがjquery 1.8だとnullを返します。

visualize.jquery.jsないの20行目あたりにそのデフォルト値を設定してい入る箇所がありますので、
下記のように変更します。

[javascript]var o = $.extend({

rowFilter: ‘*’, //’ ‘
colFilter: ‘*’, //’ ‘

},options);[/javascript]

ちなみこちらのサイトでfolkプロジェクトが進行しているようです。
オリジナルのほうはシンプルでとてもよいですが、
folkのほうはグラフごとにプラグインになっています。

プラグイン形式にしたほうが開発に広がりが生み出せますよね。

tableからグラフを作るというコンセプトは使用する側としてはわかりやすいです。
一方当然生データよりは余計なプログラムが動くことになります。

Ruby on Rails 3.2 Livestamp.js を利用してある日時からある日時までがどれだけあるのかを表示する

Rails でActiveRecord::Baseを継承したモデルのなかで普通に日付の属性にアクセスるるとその型はActiveSupport::TimeWithZoneになる。

今日から数えてその日時が何日後なのかあるいは何日前なのかといったことを表示するためにはActionViewのdistance_of_time_in_words_to_nowを利用すれば実現できます。

ローカルの時間を許容するのであれば、サーバーに負担をかけないためにローカルで動作するtimeago.jslivestamp.jsを利用するのもオススメです。

今回問題になったのはある日付からある日付までの時間を計算する必要があったことです。
まず、サーバーになるべく負担をかけないようにローカルで動作するlivestamp.js ( v1.1.1 ) を選択しました。
※livestamp.jsをどのように使うかの説明は割愛します。

このライブラリ(他のもそうですが)ある日付と現在の時間を計算して表示することを目的としていますので、上記の問題にはそぐわなかったわけです。

ちょっとトリッキーな方法で解決しました。

helpers/application_helper.rbなどに

[ror]def between_date_livestamp(from_date, to_date)
(Time.zone.now – (to_date – from_date)).to_time.iso8601
end [/ror]

などとしておいてviewで

[ror]
<span data-livestamp="<%= between_date_livestamp(@a_model.start_date, @a_model.end_date)  %>"></span>[/ror]

のようにします。

between_date_livestampメソッドで行っていることは
比較したい二つの日時の「差」を出しておいて、
現在日時からその分離れている架空の日時を返すというものです。

逆にいうとその架空の日時は現在日時から比較したい二つの日時と同じ分だけ離れているので、
本日からどれくらい離れているのかを計算するlivestamp.jsの値として利用できるわけです。

デメリット
・サーバー側で計算したときの「今日」とローカルでlivestamp.jsが計算した「今日」では少なくとも通信時間分のズレがあります。厳密さが必要なときは利用できません。
・ せっかくサーバーに負担をかけぬようlivestamp.jsを使うのに、結局サーバーでの計算が必要。
・htmlの内容に架空の(何の意味もない)日付が記述されてしまう。

 

追記:(2012/09/17)

上記にバグ(というか見落とし)ありました。

livestampは時間がたつと更新されます。「今の時間」は刻々と代わっていくけれども、終了日時は変わらないのでおかしいことになります。

livestamp.jsの中身を見てみるとpauseというメソッドがあるのですが、グローバルらしいので使えません。
あんまりライブラリはいじりたくないので、かわりにdestroyメソッドを使ってなんとかしました。

[javascript]

$(‘.live-stamp-freeze’).each(function() {
var text;
$(this).livestamp($(this).text());
text = $(this).text();
$(this).livestamp(‘destroy’);
$(this).text(text);
)};

[/javascript]

[ror]
<span class=".live-stamp-freeze"><%= between_date_livestamp(@a_model.start_date, @a_model.end_date)  %></span>[/ror]

一度livestampで値を出してからその値を変数に入れておいてlivestampをdestroyします。それから再度textメソッドを使って再設定しています。 かなり強引ですが。。

 

Ruby on Rails 3.2 rvmのgemsetでデフォルトが設定できなくてはまった件

ある日突然、rake db:migrationが動かなくなりました。エラーを吐き出すように。。rake全体がだめになっているようでコチラの記事を見つけました。内容は新しいrvmのgemsetを作って適用するというもの。解決。

と思いきや、後日再び同じ症状。もう一度同じことをしたら直りました。

案の定、再起動時に再発します。

どうやらgemsetのdefaultが設定されていない模様で、再起動時にダメーな状態に戻ってしまっているようです。いくらuse –defaultを設定してもデフォルト値が設定されないのでググッたらコチラの記事を見つけました。

rvm get head

これだけで解決。

jQuery UI dialogでcloseしてもdestroyしてもコンテンツが残る

jQuery UI dialogはclose destroyというメソッドが用意されています。
dialog.closeは文字通りdialogを非表示にするだけ。
dialog.destroyはdialogを消去します。

しかしこのdialog.destroyが曲者で、dialog内のコンテンツは消去しないようです。

動的に作ったjQueryオブジェクトに対し、dialogを作成すると、bodyタグの中に次々とごみが残っていきます。。

それを回避するためにはonCloseイベントでdialog.destroyメソッドを呼んだあと、
dialog.widgetメソッドを呼び、戻り値にremoveメソッドを呼んでやればすべて消えます。
[javascript]
scope = this
this.dialog = $(‘<div class="テスト">これはテストです</div>’);
this.dialog.dialog({
close: function(){scope.onClose()}
});
this.onClose= function(){
this.dialog.dialog("destroy");
this.dialog.dialog("widget").remove();
}
[/javascript]

「横浜生まれです」に関する反感に対するイイワケ。

仲良くしていただいている社長によく言われるのが、なんで「神奈川県出身」といわず「横浜出身」と言うの?ということ。
そこにどうやら「我々は神奈川の中でも選ばれた存在だ」という意味が含まれているように感じられるらしいです。

他県の人だけでなく、 神奈川の横浜市ではない地域の出身の方にも同様の「イヤミ」が感じられるらしいです。

許してください、そうなっちゃう感じ。

たしかに、横浜出身者は(少なくとも私の周囲では)例外なく「横浜出身です」といいます。
それはごくごく自然に自分が「横浜出身だ」と思っているからであって、なにもそれが特別であると意識しているわけではないのです。

実際、小学校・中学校ともに横浜市立、学校で習うのも「神奈川の歴史」よりも「横浜の歴史」ということのほうが多く、歌も「わがひのもとはしまぐによー」と始まる横浜の歌をまず覚えさせられる。こうして横浜出身というマインドコントロールは実現されていくのです。そういうわけで「あ、そっか横浜って神奈川県だったんだ」と思い直すのが、かなり物心がついてしまってからです。。

他の地域からするとちょっと異常に感じられるその感覚に反感があるのも当然ですが、そういった背景がございます。暖かく流してください。多くの方と同様、地元が好きなだけなんです。

jqGridのsetFrozenColumnsのイベント処理とその後のDOM構造について

javascriptをベースとしてエクセルのような機能を表現できるjqGridで最近では列固定、行固定することができるようです。

そのこと(setFrozenColumns)についてはこちらを参考にさせていただきました。

さて、setFrozenColumnsメソッドを呼ぶとのDOM構造が変わってしまいます。

それによって独自に拡張した部分の挙動がおかしくなりました。
正しく動作させるためにはsetFrozenColumns後に作られたDOMにあわせて拡張する必要があります。

そのためには以下の2つのことが必要ですが、ドキュメントにはなかったのでメモします。
※注意:この記事を書いた時点のバージョンjqGrid4.3.2におけるものであり、今後仕様が変更される可能性が高いです。

1:setFrozenColumnsが完了したというイベントを取る必要がある。

ソースを読むとどうやら、 “jqGridAfterGridComplete.setFrozenColumns”というイベントを発行しているようです。ですので

[javascript]
$grid.jqGrid(‘setFrozenColumns’);
$grid.on(‘jqGridAfterGridComplete.setFrozenColumns’, function(e){//処理})[/javascript]

とすればsetFrozenColumnsの完了イベントを受け取れます。

2:DOM変更後のテーブルを読み解く

DOM変更後は4つのテーブルに分かれます。

まず上下にテーブルが2つずつ。そしてそれぞれの左側に重なるようにテーブルが1つずつできます。このうちスクロールされるのが緑の部分というわけです。
上の二つのテーブルはクラスが”ui-jqgrid-htable’です。下の二つのテーブルには”ui-jqgrid-btable”という名前のクラスがつきます。ですので、

[javascript]hTables = $gird.find(‘table.ui-jqgrid-htable’);
bTables = $grid.find("table.ui-jqgrid-btable’);
$red_table =  $(hTables[0])
$blue_table = $(hTables[1])
$green_table = $(bTables[0])
$yellow_table = $(bTables[1])[/javascript]

とすればそれぞれのテーブルを取得できます。

Ruby on Rails 3.2 acts_as_tree から acts_as_nested_listへ乗り換えました

acts_as_treeからacts_as_nested_listへの乗り換えについては下記のリンクに書かれています。

Converting Acts_As_Tree to Awesome_Nested_Set

あーなんだ、簡単そうだ。
と思ったらこれが非常に大変でした。

アプリケーションを作る前だったら乗り換えるのは確かにこの手順を踏めばあっという間です。
しかし、アプリケーションをある程度実装している段階では乗換えの前に作戦を立てたほうがよさそうです。

まず、大前提としてacts_as_treeのほうは各カラムにparent_idを設定することでツリー構造を実現するという古典的な方法を使っていて、acts_as_nested_listのほうは入れ子集合モデルを応用しているものになります。

この違いによっていくつかのクリティカルの仕様変更を余儀なくされます。

■違い1:acts_as_treeはルートを2つ以上もてる、acts_as_nested_list:ルートは1つしかもてない

実社会でツリー構造をしているもののなかで、一番上がひとつのものは少ないのではないでしょうか。組織でも社長が一人とは限らないし、パソコンのファイルとフォルダをみても、一番上をたどっていったらフォルダがひとつなんてことはありません。acts_as_treeはparent_idをnilにすればすぐにルートになれたので、この点は単純で融通が利きました。

■違い2:acts_as_treeに順番は存在しないのに対し、acts_as_nested_listには順番が存在する。

nested_listという名前からもわかるように、acts_as_nested_listには何番目の子供かという情報があります。一方acts_as_treeにはその情報がないので、順番を設定したい場合はacts_as_listなどを追加で使う必要がありました。私も前バージョンの実装時にはこの二つをつかってツリー構造を定義していたわけです。

■違い3:acts_as_treeはdestroy時、childrenを消さないのに対し、acts_as_nested_listはchildrenを消す

厳密に言うとdescendantsを消します。acts_as_treeにはdescendantsメソッドはないので、すべての下位treeを取得する場合childrenを再帰ループさせる必要がありました。入れ子集合モデルではまさにこの点が有効で、SQLをひとつだけ発行すれば関連する親や子供を取得できることにあります。acts_as_nested_listに乗り換えた後は単にtree.destroyとするだけで子供も全部消してくれます。その際には子供のdestroyは呼ばずにdeleteで消している点も注意すべきポイントです。

さて私の行っていた実装でこれらのことがどのように影響したかということと、どのように解決したかをお話します。

■違い1に対して

どうしてもルートを2つ持ちたかったわけです。そのため空のツリーを一番上に追加するようにしました。そして、acts_as_nested_listにはいくつかルートに関するメソッドがありますが、それらを次のようにオーバーライドしました。

[ror]
def move_to_root
self.move_to_child_of(self.root)
end
def child?
!self.root?
end
def root?
self.depth <= 1 #depthを使っていなければlevel
end
[/ror]

このようにすると一番初めに強制的に作られたルートはずーっとルートのままになります。move_to_rootを呼ぶと実際にはrootの子供として設定されます。そして、root?やchild?もルートのすぐ下の子供をrootと認識するようになります。ただしrootメソッドだけは返すツリーはひとつと決まっていますのでそれは本来のrootを返すままになっています。わかりやすくなったかは微妙ですが、使いやすくなったことは確かです。

■違い2に対して

結論から言うとacts_as_nested_list + acts_as_listを併用して使うということに落ち着きました。事情としては私の作ったUIにあわせるため、併用したほうがよさそうだったからです。

まず最大の利点としてはツリー構造を表現する歳にSQLを単純にできたことでした。普通の考えであれば一番上のtreeを取得しそれにchildrenでループさせ、さらにchildrenがあれば、、、と再帰ループさせてツリーを表現します。しかし、それにはどうしてもchildrenを取得するためのSQLが発行されてしまいます。しかし順番が正しくてそれぞれの深度さえわかれば(acts_as_nested_listではoptionでdepthを保存しておけます)ツリー構造を表現できるので、

[ror]@trees = Tree.order(‘position’).all(id)[1..-1][/ror]

とし、view側で

[ror]<% @trees.each do |tree| %>
<li class="depth_<%=tree.depth%>"><%= tree.name %></li>
<% end %>[/ror]

とし、cssでマージンを設定すればよいです。若干冗長ではありますが、scssを用いて

[ror]$margin: 20px;
@for $i from 0 through 40 {
li.depth_#{($i+1)} { margin-left: $margin * $i}
}[/ror]

とすればだーっと作成してくれます

厄介だったのはacts_as_listでのpositionとacts_as_nested_listにて設定されている何番目の子供かという情報を完全につじつまを合わせる必要があることです。いくつかのロジックを組むことで一応実現できましたが、まだvalidationをするにはいたっていません。
実装しているUIとしては、ツリーを「上、下、右、左」に移動することで階層構造を変更することができるようなものが必要でした。たとえば、
ツリー1
└ツリー2
└ツリー3
ツリー4
とあるとして、「ツリー3を左へ」とすると
ツリー1
└ツリー2
ツリー3
ツリー4
となってほしいというような仕様になります。

この場合ツリー構造の視点から考えると「ツリー3をルート」の子供にするということがいえます。そうしたければacts_as_nested_listのmove_to_child_ofメソッドを呼べばすみます。しかしmove_to_child_toメソッドは最後の子供として追加してしまうためツリー3はツリー4の弟になってしまいます。何番目の子供にするのかを指定しなければなりません。acts_as_nested_listにはmove_to_child_with_indexメソッドというのがあって、それを実現できます。「上へ」や「下へ」とする場合は兄弟関係が変わります。その場合はpositionも変わります。ツリー構造の変更時にはpositiontと何番目の子供かという情報につじつまを合わせるようにコードを変更する必要がありました。これはデータとしては冗長的です。しかしそうしないことで、データの取り出す時にその取り出し方が冗長的であるならば、どっちかをとるしかありません。

■違い3について

acts_as_nested_listでは親に対しdestroyするとその関連する子供も消すというのは、とても利にかなっていると思えました。実際必要なコードも少なくなり、非常に有効に思えました。しかしdependent destroyがあるとちょっと厄介です。

私の場合はtreeは抽象クラスとしてpolymorphicにしています。つまりtreeはツリー構造だけを実装し、実際にはそのツリーに必ずひとつくっついている別のモデルがあるわけです。こうすることでアプリケーションにあるいくつかのツリー構造をしたオブジェクトを一括で管理することができます。(実はこの点は後悔する部分があります。polymorphicはデータベース対して使ってしまうとそのテーブルだけ肥大しやすくなるからです。委譲にしとけばよかったかなー。と。)

問題はacts_as_nested_listのdestroyメソッドを呼ぶとdescendantsに対しdeleteメソッドを呼ぶことにあります。そうなるとdependent destroyとしているオブジェクトが亡霊のようにデータベースに残ることになります。コレを回避するためにはbefore_destroyを定義して消そうとしているオブジェクトのdescendantsを走査し、あらかじめ関連オブジェクトを消しておく必要があります。

[ror]before_destroy :destroy_tree_items
belongs_to :tree_item, :polymorphic => true, dependent: :destroy
self.descendants.each do |tree|
tree.tree_item.destroy
end[/ror]

実際には消してしまいたいヤツと消したくないやつとあったのでもう少し複雑ですが、まこんなところです。

現段階でのファイルを張っておきます。特異なコードなので誰の役に立つかわかりませんが、。そのうちプラグイン化したいものです。

Ruby on Rails 3.2.0: has_many belongs_to association で結合している場合、includeオプションを使うとよい

AR.findなどでSQLを発行する際にincludeオプションを付けると
冗長なSQLが改善されることは知っていました。
しかし
posts - posts_writers - writers - people
というようにwritersが実際にはpeopleであるような多態性を持たせたアソシエーションの場合、
Postモデルからどのようにpeopleをincludeしておけばよいか悩んだのでメモ。
結論としてはモデル側のアソシエーション定義で
includeオプションを付けるとよいことがわかりました。 
[ror]
class Post < ActiveRecord::Base
has_many: writers,<strong> :include=>person</strong>
has_many: viewers,<strong> :include=>person</strong>
end

class Writer < ActiveRecord::Base
belongs_to :post
belongs_to :person
end

class Viewer< ActiveRecord::Base
belongs_to :post
belongs_to :person
end
[/ror]

このようにすることでコントローラー側で

[ror]
@post = Post.includes(:viewers).find(params[:project_id])
[/ror]

としたときにあらかじめ関連付けられたpeopleのレコードを読み込んでくれる

[sql]
SELECT "people".* FROM "people" WHERE "people"."id"
IN (13885, 13886, 13887, 13888, 13889, 13890, 13891, 13892)
ORDER BY updated_at
[/sql]

そうするとview側で

[ror]<% @post.viewers.each do | viewer| %><%= viewer.person.name %><% end %>[/ror]

としても都度SQLを発行することはないです。