2007/12/27

End Of 2007年


早いもので、今年も残すところあとわずかとなりました。



まずは、本年お世話になったお客様に感謝です。

本年もご愛顧いただきまことにありがとうございます。

来年も変わらぬご愛顧のほど、よろしくお願い申しあげます。



今年を振り返ってみると、瞬く間に過ぎ去っていった一年でした。

昨年の反省から、今年は、よりアンテナを伸ばし情報収集を怠らず、時代の流れに素早く乗っていこうとの思いでやってきましたが、結局、情報に埋もれて身動きが取れなかった気がします。

Googel Readerで、未読フィード数が100+から1000+になって、バージョンアップしたことに気がついたようでは駄目ですね。



来年は、情報を的確にさばき、受信のみならず、さらなる発信も行っていきたいと思います。



そして、このブログのタイトルにもある「守破離」ですが、これまでは、「守」を意識してきましたが、来年からはそろそろ「破」の段階にいかねばなりません。

これまでの経験を活かし、さらなる精進を重ねていこうと思う次第です。


守破離とは

「守」とは、


師匠の教えを正確かつ忠実に守り、剣道における基本の作法、礼法、技法を身に付ける、いわば「学び」の段階をいいます。


「破」とは、


それまで身に付けた技や形をさらに洗練させ、自己の個性を創造する段階をいい、


「離」とは、


さらに前進させ、自らの新しい独自の道を確立させる最終段階のことをいいます。自己を常に発展させるべく修行、精進を重ねていく終わりのない道です。




それでは、皆様、よいお年を!

2007/12/20

はてなダイアリーキーワードのふりがなを表示する、Firefoxの拡張機能(Extension)を作ってみました

HatenaKeywordTrans - Firefox Extension



Blog等を読んでいるとき、「これ、なんて読むんだろう?」と思う単語(キーワード)に出会うことがよくあります。

そんなとき、都度、きちんと調べられるといいのですが、面倒なのでなかなかそうはいきません。

この間も、「Leopard」や「Erlang」に遭遇し、適当に「れおぱーど」「えあらんぐ」などと脳内変換していました。orz



そんなわけで、Firefoxで選択したキーワードのふりがなを表示する拡張機能を作ってみました。

ふりがなの取得は、はてなダイアリーキーワードAPIを使っています。



Firefox2からは、RSSを簡単に扱える、Feed content access APIが使えるのではじめはこれを使おうと思ったのですが、はてなダイアリーキーワードのAPI(RSS)では、ふりがなはhatena名前空間による拡張(hatena:furigana)により定義されているので、nsIFeedContainer::fieldsのgetProperty("hatena:furigana")で取得します(と思う)。

が、これがなぜかうまくいかなかったので、Feed content access APIを使うのは諦めました(涙



また、日本語にロケールする場合、日本語はJavaユニコード(Unicode)形式に変換する必要があるので、3rdpageSearch JpJavaユニコードコンバーターで変換させていただきました。



対応バージョン


Firefox: 1.5 – 2.0.0.*





インストール



hatenaKeywordTrans-0.1.0.xpi ver 0.1.0 (2007/12/20)


使用方法



インストール後、気になる単語を選択し、右クリックでコンテキストメニューを表示します。

メニューに、「はてキ変換:xxx」が追加されていますので、カーソルを当てるとふりがなが表示されます。


変更履歴



ver 0.1.0 (2007/12/20)

初回公開


参考サイト



下記のサイトや拡張機能を参考にさせていただきました。



ありえるえりあ

Firefox拡張機能(extension)の作り方

gTranslate

選択した文字をGoogleで翻訳

Sage

FirefoxのサイドバーでRSSリーダ

2007/12/11

[再] Bloggerのクラシックテンプレート(FTP公開)でもラベル一覧を表示したい


以前にBloggerのクラシックテンプレート(FTP公開)でもラベル一覧を表示する方法を紹介したのですが、不具合が発見されたので再エントリーします。



発見された不具合は、ラベル名にスペースがある場合マルチバイト文字と誤判定しBase64エンコードしてしまうというものです。

URLエンコードした際に"%"の有無で判定していたのですが、これではスペース(%20)等の記号を含む場合にうまくありません。



そしてさらに、Bloggerという文字列がラベルに含まれていた場合、Base64エンコードではなく、URLエンコードになるという現象も確認しました。

Bloggerという単語以外にも発生するのかは不明です・・・。だれか詳しい方教えてください(泣



というわけで、修正版は下記からお願いいたします。折角ですので、コード生成機を作成しました。

当記事を参考にされた方、すみませんでした!お手数ですが、修正をお願いいたします。



なお、前回同様下記コードの実行には別途Base64エンコードのライブラリが必要です。

Free code and tutorialsにある、Javascript base64 encoding等を予め、読み込ませる必要がありますので、ご注意ください。


Update:

2008/01/29現在、http://www.blogger.com/feeds/UserID/blogs/BlogID?alt=json-in-script&callback=listLabelsというリクエストでエラーが帰ってきてしまいます。

調べてみると、同じ現象にあっている人がいるようですが、残念ながら解決策はまだないようです。

Public Metafeed Callback Error - Blogger Data API | Google グループ

※中桐 秀起さん、コメントありがとうございます!


Blogger Data APIが変更になって、Google AJAX APIからmetafeedを取得するようになった気がするのですが、既存のコードをあまり修正しないように対応してみます。

単純に、全ポストデータを取得しラベルを抽出します。

しかしながら、ラベルを取得するのに、全フィードを取得しなければいけないので、
もっとスマートなやり方があれば是非お知らせください!


Update2:

http://www.blogger.com/feeds/UserID/blogs からは、callbackが使えるようなので、ユーザのブログ情報を取得し、指定のBlogIDのCategory(ラベル)を表示するように修正しました。


コードは下記の生成機より、取得できます。

念のためこれまでのコードは、[Genarate old]から取得できます。























ラベルリスト生成機
UserID:プロフィールページのURLの最後等
例)http://www.blogger.com/profile/08755644619888194912
BlogID:投稿画面URLの最後等
例)http://www.blogger.com/posts.g?blogID=1303966254927872449
ベースURL:ラベルディレクトリのURLまたはパス
タイトル:リストのタイトル
FTP公開:FTP公開モードの場合チェック

    



2007/12/09

チェックアウトしたフォルダから.svnフォルダを削除したい


Subversionでバージョン管理している場合、リポジトリからチェックアウトすると、管理フォルダの.svnフォルダができます。

その後、バージョン管理の対象から外したい場合には、Subversionのエクスポートを使用するか、.svnフォルダを削除する必要があります。



ここでは、コマンドプロンプトから(DOSコマンドで)削除する方法を紹介します。



下記コマンドを、.svnフォルダを削除したいフォルダに移動してから実行します。サブフォルダも対象になります。


for /R %i in (.svn) do rd /Q /S "%i"




他にも、Dreamweaverの管理フォルダである「_note」や、WindowsのサムネイルDBファイルの「Thumbs.db」もまとめて消してしまうように、バッチファイルを作成しておくと便利かもしれません。


for /R %%i in (.svn) do rd /Q /S "%%i"
for /R %%i in (_note) do rd /Q /S "%%i"
for /R %%i in (Thumbs.db) do del /Q /S "%%i"

2007/12/06

FON Simple Maps

先日、本人のブログより公開された「FON Simple Maps」ですが、iGoogleディレクトリに無事登録されたようです。
このガジェットの詳細、フィードバック・感想などありましたら、こちらへお願い致します。

2007/11/30

VBAのReplace

VBAには、指定された文字列の一部を、別の文字列で指定された回数分で置換した文字列を返す、Replace 関数があります。



先日、ユーザから入力された文字を、日本語:全角、英数字:半角に整形するモジュールで、「う」が「ウ」に変換されてしまう不具合が見つかりました。

このモジュールではReplace関数を使い、以下のように置換している箇所がありました。


formatString = Replace(strResult, "ウ", "ウ")


指定しているのは半角の「ウ」なのですが、なぜか「う」も置換されてしまいます。



ですので、以下のように、文字列式を評価するときに使用する文字列比較のモードをバイナリ モードで比較するようにして対処しました。


formatString = Replace(strResult, "ウ", "ウ", Compare:=vbBinaryCompare)

2007/11/25

FON Simple Maps を iGoogle Gadgets で作ってみました

Google Developer Day 2007に参加した際に、Google Gadgets APIのセッションを聞いてから、なにか作ってみようと思ったものの、時間だけが経過してしまいました・・・。


FONというWiFiコミュニティがあるのですが、そのFONのWiFiネットワークを表示するiGoogle Gadgetを探したのですが、あまり見当たらなかったので、せっかくなので勉強がてら自分で作ってみようじゃないかと。(自宅ネットワークの無線化のために、無線LANルータであるラ・フォネラを激安で購入済みです)

FONについて、詳しくはこちら



というわけで、実際に作ったものがこちらです。




使い方は簡単で、マップの下の検索ボックスに住所等を入力し、FONスポットを検索するだけです。

マップの上の「この場所を保存」をクリックすると、次回からこの場所が初期画面になります。

アイコンの説明は以下のとおりです。










1時間以内にアクティブになったFONアクセスポイント
その他のFONアクセスポイント
パーソナライズされたFONアクセスポイント



iGoogle Gadgetsを実際に作ってみた感じたことは、これはすごいなということですね。

Ajax等の仕組みも用意されていますし、直感的に作っていけるのではないでしょうか。

そしてなにより、ドキュメントがしっかりしているので、躓いても何とかなります。



今回の件で、久しぶりにGoogleAPIドキュメントを眺めたのですが、Maps APIも大分変わっていて、多くの機能が追加されていて驚きました。

ドキュメントも統合された感じで非常に見やすくなった気がします。



次は、Google Data APIにチャレンジしてみようかと思っています。

2007/10/05

CentOS4.5にて、DRBD/hearbeatでサーバ冗長化


先日(といっても、結構時間が経ってしまいましたが・・・)、Linuxサーバを冗長化する機会がありました。



その際に、ドキュメントを用意したのですが、一部異なるアプローチをとったところがあったので、そのあたりをメモしておこうと思います。

ドキュメントはこちら

HAクラスタ構築手順書



其の一 DRBDパーティション



まず、DRBDでネットワークミラーリングを構築するのですが、マニュアルでは第2SCSIディスクを想定していますが、今回は、ディスクが一つしかないので、既存のディスクにパーティションを作成する必要がありました。

空き領域に新たなパーティションを作成するのですが、/(root)パーティションで全部使っていて空きは無かったので、やむなく再インストール・・・



せっかくですので、この機会に自由にサイズ変更をできるというLVMでパーティションを作成し、DRBDをセットアップです。


DRDBパーティション(論理ボリューム)の作成
$ sudo lvcreate -L 10G -n drbd main

$ sudo vi /etc/drbd.conf
resource r0 {

protocol C;

incon-degr-cmd "echo '!DRBD! pri on incon-degr' | wall ; sleep 60 ; halt -f";

startup {
degr-wfc-timeout 120; # 2 minutes.
}

disk {
on-io-error panic;
}

syncer {
rate 100M;

group 1;

al-extents 257;
}

on host1 {
device /dev/drbd0;
disk /dev/main/drbd;
address 192.168.0.221:7788;
meta-disk internal;
}

on host2 {
device /dev/drbd0;
disk /dev/main/drbd;
address 192.168.0.231:7788;
meta-disk internal;
}
}

其の二 ミラーリングデータはシンボリックリンクで



既存のアプリケーションがあるため、設定ファイル等はなるべく変更したくありません。

そこで、設定ファイルはそのままに、データディレクトリをシンボリックリンクで参照するようにしました。


アプリケーション及びWebデータ
$ sudo -u user mkdir /data/application
$ sudo -u user ln -s /data/application /home/rms/application
$ sudo -u user tar cpzf /home/user/old_htdocs.tar.gz /home/user/htdocs
$ sudo -u user mv /home/user/htdocs /data/user_htdocs
$ sudo -u user ln -s /data/user_htdocs /home/user/htdocs
$ sudo ls -l /home/user
$ sudo ls -l /data

MySQLデータ
$ sudo -u mysql tar cpzf /home/mysql/old_data.tar.gz /home/mysql/data
$ sudo -u mysql mv /home/mysql/data /data/mysql_data
$ sudo -u mysql ln -s /data/mysql_data /home/mysql/data
$ sudo ls -l /home/mysql
$ sudo ls -l /data


その他、heartbeat等はマニュアルどおりでおおむねいけました。

マニュアルを作成してくれたK氏には感謝です!



DRBD/hearbeatでサーバ冗長化は、手軽にできてかなりおススメです!

自動でフェイルオーバー/フェイルバックする様子には、本気で感動しました。

この機会に(?)、是非挑戦してみてください。



参考書籍:


2007/09/10

Linux kernel 2.6 で Beep が鳴らない


先日、CentOS4.5にて、heartbeat/DRBDによるサーバ冗長化の作業がありました。

その際、障害発生によりプライマリサーバからセカンダリサーバに切り替わるときは、音を鳴らして知らせることになりました。

そこで、良くあるBeep音(ピーピーと鳴く、アレです)を鳴らすことにしたのですが、VBのようにBeepというコマンドでもあって簡単に鳴らせるのだろうと思っていたのですが、なかなか鳴らずに躓いてしまったので、メモしておきます。



まず、Beepというコマンドはないのか?と調べたところ、けんども日記: Linux でビープ音を鳴らすにて、紹介されていました。

これをテストマシンのCentOS4.4にて試してみたのですが、別段エラーログもなく、音は鳴りませんでした。



beepコマンド
$ wget http://johnath.com/beep/beep-1.2.2-1.src.rpm
# rpmbuild --rebuild beep-1.2.2-1.src.rpm
# rpm -ihv /usr/src/redhat/RPMS/i386/beep-1.2.2-1.i386.rpm

$ sudo beep -f 2500 -l 240


では、単純にスピーカから音を出すにはどうしたらいいのか?

と、たどり着いたのが、 [BEL] コマンドの終了を音で知らせる

さっそく、

printf "\7"

としましたが、これでも音は鳴らず・・・



これはおかしいと思い、他のマシン(RHEL3)で試してみるとあっさり音が鳴りました。

両サーバの違いは何かと、サウンドの設定等色々調べてみると、結局、Linux kernel 2.6からは、デフォルトでPCスピーカーはOFFになっている。ということでした。

どうりで、kernel 2.4のRHEL3では鳴ったわけです。


# sudo modprobe pcspkr
# printf "\7"
リブート後も有効に
# vi /etc/rc.local
/sbin/modprobe pcspkr


これで、先にインストールしたBeepコマンドでも音がなり、カエルの歌をBeepで演奏することができるようになりましたw



余談ですが、「Linux Beep」で調べると、目的とは逆の「Beepを消す」といったものがガンガンヒットしました。

たまにコンソールから作業するときにTab補完失敗でピーピーうるさい件をどうにかする方法がありました。


LinuxコンソールのBEEP音を消す! (技術メモ)

vi /etc/inputrc

#set bell-style none


これで静かに作業することができます。思わぬ収穫でした。

2007/07/24

PXEでCentOSをネットワークインストールする


新しく用意したマシンにCentOSをインストールしようとしたのだけれど、なんとこのマシンにはCDDもFDDもついてなかった!

というわけで、PXEネットーワークブートを使用してCentOSをインストールすることにしました。


PXEネットワークブート用サーバを構築



まずは、PXEネットワークブート用のサーバを構築します。

「@IT:PXEネットワークブート用サーバを構築するには」

「PXEを使ったネットワークブート」

を参考にしました。

開発用のサーバとして使用しているCentOS4.4マシンをPXEサーバにすることにします。



TFTPサーバを構築

tftp-serverをインストール
# rpm -qa | grep tftp
# yum install tftp-server
Installed: tftp-server.i386 0:0.39-2
Complete!

/etc/xinetd.d/tftpを編集し、サービスを有効にする
# vi /etc/xniinetd.d/trftp
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /tftpboot
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
# service xinetd restart
xinetd を停止中: [ OK ]
xinetd を起動中: [ OK ]

PXE用ブートイメージを取得
# mkdir /tftpboot/pxe_centos4.5
# cd /tftpboot/pxe_centos4.5
# wget ftp://ftp.riken.jp/Linux/centos/4.5/os/i386/images/pxeboot/vmlinuz
# wget ftp://ftp.riken.jp/Linux/centos/4.5/os/i386/images/pxeboot/initrd.img
# ls
initrd.img vmlinuz


DHCPサーバを構築

dhcpをインストール
# rpm -qa | grep dhcp
dhcpv6_client-0.10-14_EL4
# yum install dhcp
Installed: dhcp.i386 7:3.0.1-59.EL4
Complete!

設定ファイルを編集 ※ 不要な行は削除しています
# cp /usr/share/doc/dhcp-3.0.1/dhcpd.conf.sample  /etc/dhcpd.conf
# vi /etc/dhcpd.conf
ddns-update-style interim;
ignore client-updates;

subnet 192.168.0.0 netmask 255.255.255.0 {
option routers 192.168.0.1;
option subnet-mask 255.255.255.0;
option domain-name "r-stone.net";
option domain-name-servers 192.168.0.2;
option time-offset -18000; # Eastern Standar
d Time
filename "/pxe_centos4.5/pxelinux.
0";
range dynamic-bootp 192.168.0.250 192.168.0.254;
default-lease-time 21600;
max-lease-time 43200;
}
# mkdir /var/lib/dhcpd
# touch /var/lib/dhcpd/dhcpd.leases
# service dhcpd start
dhcpd を起動中: [ OK ]


PXEサーバを構築

syslinux(pxelinux)のインストール (既にインストール済みでした)
# rpm -qa | grep syslinux
syslinux-2.11-1

ブートローダの準備
# cp /usr/lib/syslinux/pxelinux.0 /tftpboot/pxe_ccentos4.5/

設定ファイルの作成
# mkdir /trftpboot/pxe_centos4.5/pxelinux.cfg
# vi /tftpboot/pxe_centos4.5/pxelinux.cfg/default
default centos4

label centos4
kernel vmlinuz
append load initrd=initrd.img devfs=nomount


ファイアウォールの設定

これまで構築したサーバで使用するポートを開放














サーバポートプロトコル
DHCP67UDP
TFTP69UDP
PXE4011UDP

###
# DHCP
###
iptables -A INPUT -p udp -s 192.168.0.0/24 --dport 67 -j ACCEPT

###
# TFTP
###
iptables -A INPUT -p udp -s 192.168.0.0/24 --dport 69 -j ACCEPT

###
# PXE
###
iptables -A INPUT -p udp -s 192.168.0.0/24 --dport 4011 -j ACCEPT


CentOSのイメージをマウント&HTTP公開


ISOイメージをマウント
# mkdir /mnt/iso
# mount -t iso9660 -o loop /home/r-stone/iso/CentOS-4.5-i386-binDVD.iso /mnt/iso

Apatchで公開
# vi /usr/local/apache2/conf/httpd.conf
Alias /centos4.5 "/mnt/iso"
<Directory /mnt/iso>
Options MultiViews Indexes FollowSymLinks
Order deny,allow
Deny from all
Allow from 192.168.0.0/24 127.0.0.1
</Directory>
# /usr/local/apache2/bin/apachectl restart



PXEネットワークブートでCentOSをインストール


いよいよCentOSをネットワークインストールします。

こちらは、

「@IT:PXEネットワークブートでLinuxをインストールするには」

を参考にしました。



インストール方法の設定


PXEブートよりインストーラが起動してしまえば、あとは通常のインストールと同じです。

ただ、パッケージの転送はHTTPを使用するようにしましたので、インストール方法の画面では「HTTP」を選択し、HTTPの設定を行います。

インストール後


PXEサーバ側:

念のため使用後はサービスを停止しておきます

  • HTTP公開の停止

  • イメージのアンマウント

  • TFTPサーバの停止

  • DHCPサーバの停止


クライアント側:


  • BIOSのPXEを無効に





CDDがなかったのは焦りましたが、結局CDDなんてインストール時にしか使わないわけで、消費電力を抑えるためにもPXEでのネットワークインストールも良いかなと思います。

2007/07/20

Bloggerのクラシックテンプレート(FTP公開)でもラベル一覧を表示したい


07/12/11追記:下記スクリプトに不具合が見つかりました。こちらの記事を参照してください。



弊社Official Blogでは、Bloggerのクラシックテンプレート(FTP公開)でブログを公開しています。

記事の投稿時には、「この投稿のラベル」というところでラベルを設定できるのですが、設定したラベルの一覧をサイドバーに表示するタグは無いようなのです。


クリボウの Blogger Tips: ラベル一覧にフィードアイコン

クラシックテンプレートは…


クラシックテンプレートの利用者は、上に示したようなカスタマイズができません。というより、それ以前にブログにラベル一覧を表示する方法が用意されていません。




(クラシックテンプレートには、)サイドバーに全てのラベルを表示するタグはありません。サイドバーのラベルウィジェットを使う場合には、レイアウトテンプレートに変更する必要があります。
(クリボウ訳)



レイアウトテンプレートを使えない身(FTP 公開ブログ)としては、非常に残念です…。


なにか他の方法で表示できないかと調べていると、Javascriptでサイドバーにラベル一覧を表示する方法を発見しました!


phydeaux3: Automatic List of Labels for Blogger Classic Templates / FTP


Caveats - this only works for blogs that have their admin profile publicly available, and the blog must be publicly listed in that profile (this is as it should, if you haven't announced your blog publicly, then your metafeed shouldn't be public). It also does NOT return the number of posts in each label. Just the list of all the ones used.



Ok, you need two pieces of information for it to work. Your Blogger UserID number, and your Blogs ID number. Both of these you can get via your dashboard. For the USERID, click on the View Profile link and it's the long number at the end of that url. For the Blog ID number, again from the dashboard if you click on any links to change settings or create a post for that blog, all links will have blogID=XXXXXXX at the end where the X's will be that particular blog's ID number. Once you have that, here is code that will fetch and display the labels for your blog.




どうやら、プロフィールを公開している状態で、UserIDとBlogIDがあれば可能なようです。

上記サイトより早速コードを拝借して試してみると、日本語のラベルページにジャンプできません!

Bloggerより生成されたラベルページのファイル名を良く見てみると、なんと日本語が混じるとBase64でエンコードされたファイル名になっています。ですが、上記コードでは単純にencodeURIComponentしているだけのようです。海外ではこれでOKですが、日本ではちょっとまずいです。

というわけで、前置きが長くなりましたが、以下が改造後のソースです。

※Base64のエンコードには、Free code and tutorialsにある、Javascript base64 encodingを使用しています。

このファイルを予め読み込んでおく必要があります。


<div id="labelList"></div> <script type="text/javascript">
//<![CDATA[
function listLabels(root){
var baseURL = '/blog/labels/';
var baseHeading = "ラベル";
var isFTP = true;
var llDiv = document.getElementById('labelList');
var entry = root.entry;
var h2 = document.createElement('h2');
h2.className = 'sidebar-title';
var h2t = document.createTextNode(baseHeading);
h2.appendChild(h2t);
llDiv.appendChild(h2);
var ul = document.createElement('ul');
ul.id = 'label-list';
var category = entry.category;
labelSort = new Array();
for(p in category){
labelSort[labelSort.length] = [category[p].term];
}
labelSort.sort();
for (var r=0; r < labelSort.length; r++){
var li = document.createElement('li');
var a = document.createElement('a');
if(isFTP){
var l = encodeURIComponent(labelSort[r]);
if (l.indexOf('%', 0) >= 0) {
var reg1=/\//g;
l = Base64.encode(new String(labelSort[r]));
l = l.replace(reg1, "__");
}
a.href = baseURL + l +'.html';
}
else {
a.href = baseURL + encodeURIComponent(labelSort[r]);
}
a.innerHTML = labelSort[r] + ' ';
li.appendChild(a);
ul.appendChild(li);
abnk = document.createTextNode(' ');
ul.appendChild(abnk);
}
llDiv.appendChild(ul);
}
//]]>
</script>
<!--
The script source URL must be
http://www.blogger.com/feeds/<UserID>/blogs/<BlogID>?alt=json-in-script&callback=bloggerLabels
You can get your <UserID> at the end of your profile view URL.
And you can get your <BlogID> at the end of URL in your blog editor (and blog setting)
like http://www.blogger.com/posts.g?blogID=xxxxx, in this case xxxxx is your <BlogID>.
-->
<script type="text/javascript" src="http://www.blogger.com/feeds/UserID/blogs/BlogID?alt=json-in-script&callback=listLabels" ></script>


baseURLや、baseHeading等の値は環境に合わせて変更します。

詳しくは元記事をご覧下さい。

2007/07/17

Getting Realでいこう!


2ヶ月くらい前に、はてなブックマークより[Getting Real by 37signals]というページを発見しました。



Getting Real は、より速く、よりよいソフトウェア構築のための方法です。またその主要なアイディアは多くのビジネス・クリエイティビティの現場でも採用できるものです。


とても身にしみる内容で、非常に参考になりました。頭のなかにあった漠然としたもやもやが、一気に吹き飛んだ感じでした。とってもすっきりします。

読んでるとなんだかモチベーションがあがってきて、不思議な癒しを感じられますw。まだ読んでいない方は、是非一読することをお勧めします。

これからは、「Getting Realでいこう!」ですね。



37signalsといえば、ruby on railsの作者であるDHH氏がおられるところです。また、Basecamp(プロジェクト管理アプリケーション)等のメジャーなWebサービスも提供しています。

2007/06/26

Rails API を読む


Railsに限らず、Documentは非常に重要で、とても参考になるものです。

いつもはRails Framework Documentを参考にするのですが、他に以下のようなサイトもあるようです。知らなかった・・・w



Ruby on Rails Manual
過去のバージョンのDocumentも揃っています。



Rails API with the AJAX flavor
AjaxでSuggestしてくれるので便利!



gotAPI/HTML - Instant search in HTML and other developer documentation
AJAX and Frameworks(Prototype.js等)や、HTML/CSS/Javascript等、Rails以外のも多数載ってます。こちらもAjaxでSuggest!これはいい!

2007/06/21

Edge Railsとruby-Gettext


先日、新しいRailsプロジェクトを作る機会がありまして、せっかくなのでRESTfulなRailsでいこうと思い、Edge Rails使うことを決意。



ですが、さっそく躓いたので、以下問題と解決です。ご参考までに。



アプリを起動するとエラーが発生し、development.logに以下のエラーが。

DISPATCHER FAILSAFE RESPONSE (has cgi) Wed Jun 20 21:18:28 +0900 2007
Status: 500 Internal Server Error
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
C:/ruby/lib/ruby/1.8/cgi.rb:1165:in `[]'
C:/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/lib/gettext/locale_cgi.rb:26:in `system'
C:/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/lib/gettext/locale.rb:88:in `system'
C:/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/lib/gettext/locale.rb:96:in `default'
C:/ruby/lib/ruby/gems/1.8/gems/gettext-1.9.0-mswin32/lib/gettext/rails.rb:276:in `render_file'
:
:



[gettext-u-en] Problem with gettext 1.9.0 and RESTful rails appを参考に、問題解決(ここまでくるのに、数日の間Google先生に質問攻めでした・・・)

--- /opt/local/lib/ruby/gems/1.8/gems/gettext-1.9.0/lib/gettext/locale_cgi.rb 2007-05-28 16:11:27.000000000 +0300
+++ Desktop/locale_cgi.rb 2007-05-28 16:11:49.000000000 +0300
@@ -23,7 +23,7 @@ module Locale
def system
return @@default_locale unless @@cgi
cgi_ = cgi
- if ret = cgi_["lang"] and ret.size > 0
+ if not cgi_.params.empty? and ret = cgi_["lang"] and ret.size > 0
elsif ret = cgi_.cookies["lang"][0]
elsif lang = cgi_.accept_language and lang.size > 0
num = lang.index(/;|,/)



上記問題が発生したのは、

svn co http://dev.rubyonrails.org/svn/rails/trunk rails

でとってきたEdge Railsでした。

今しがた、再度Edge Railsを取り直したら上記問題は発生せずでした・・・

rake rails:freeze:edge TAG=rel_1-2-3



なんだったんだろw

2007/06/11

Enter キーでの Submit を抑止する方法


ときに、EnterキーでFormがSubmitされてしまうと、よろしくない場合があります。

そんなときは、以下のようにするとEnterキーによるSubmitが抑止されます。


function enterSubmit(event) {
event = event || window.event;
if (event.keyCode == 13) {
if (event.srcElement) {
if (event.srcElement.type != 'submit' &&
event.srcElement.type != 'textarea') {
return false;
}
} else if (event.target) {
if (event.target.type != 'submit' &&
event.target.type != 'textarea') {
return false;
}
}
}
}

<form action="#" onkeydown="return enterSubmit(event)">
<input type="text" />
<input type="submit" />
</form>


これでまたひとつ、すっきりしましたね。

2007/06/04

Firefoxでページ内にカーソルが出現する


しばらく前から、Firefoxでページを表示するとカーソルが出現するようになった。

とても邪魔くさくてなんとかしたいと思いつつ放置していたのだけれど、本日解決しました。



先日のGDDレポートにトラックバックをくださったせつないぶろぐにて解決方法が紹介[firefoxでページ内にカーソルが表示される件について]されていました。



で、解決方法はというと、F7キーを押すだけです。


F7キーを押すとキャレットブラウズモードのオンオフを切り替えます。この機能を有効にするとWebページ中に移動可能なカーソルが表示され、キーボードでテキストを選択できるようになります。

とのことです。



いやー、とてもすっきりしました!

やっぱり放置はいくないですね。

2007/06/02

Google Developer Day 2007



5/31に世界同時開催された、Google Developer Day 2007 にいってきました。

北海道からはるばるの参加でしたが、とても有意義な時間を過ごすことができました。

開発者としてとてもよい刺激を受けたとともに、僕の中でのGoogle好感度が格段にアップしました。



Kynote & Speech


ご挨拶 - グーグル株式会社 エンジニアリング ディレクター マグラス みづ紀




まずは挨拶から。

Google初の世界同時イベントで、このDeveloper Dayには世界で5,000人が参加しているとか。

世界10カ国で同日開催されるこのイベントは、シドニー会場に続き、東京会場が二番目で、Google本社のMountain Viewが最後です。

(ご挨拶されたマグラス みづ紀さんはとても美しい方でした!)



基調講演 - Google,Inc. UberTechLead/Manager Greg Stein




Greg Stein氏の講演は、Googleのオープンソースについての考え方でした。


  • Googleのオープンソース活動は2002年頃から始まり、その頃はまだGoogle SOAP Seach APIしかなかった

  • 2005年頃から、Google Maps API、Google Code等、続々APIが公開される

  • sitemaps.orgは、Google,Microsoft,Yahooで設立し、CreateiveCommonsLisenceを用いている

  • ライセンスをCreativeCommonsにすることで、利用者に安心感を与えることができる

  • 自社のライセンスはつくらない。Apache、BSD、GPLを使用

  • ソースコードの80-90%は公開しても問題ない

  • オープンソースは市場を劇的に変える - Amazon,eBayの出現

  • Googleはインフラ(APIs)を提供

  • iGoogle,Mappletsを利用すれば、世界中のGoogleユーザへのリーチを得ることができる






ゲスト講演 - 株式会社はてな 取締役(最高技術責任者) 伊藤 直也




はてなの伊藤直也さんからは、はてなのサービスの紹介や、はてなのサービス作りの基盤は「クリエイティビティ」「コミュニティを信じる心」「技術」。「WebAPIは技術者をempowermentし、サービスによってユーザもempowermentする」というお話がありました。

いつもブログ等で拝見しておりましたが、こうして直接話しが聞けてとても刺激をうけました。



グーグル最新情報 - グーグル株式会社 シニア プロダクト マネージャー 及川 卓也




及川さんからは、Googleの最新情報がありました。

Google Codeの日本語化がされるようです。これはとてもありがたいことです。

iGoogleガジェットコンテストが開催されるようです。これは是非とも参加するしかないでしょう!

そして本日のサプライズ!Google Gearsの発表です。

GoogleGearsはWebアプリケーションがオフラインでも動作するようになるブラウザ拡張です。

他にもJavascriptを効率的に動作させる機能もあるようです。これはすごい!

前々からGoogleReaderがオフラインでも読めるといいのにと思っていましたが、早速GoogleReaderはGoogleGearsに対応しているようです。

このほかにも、「5分で出来るGoogleツールバーAPIを使ったカスタムボタンの作成」も披露してくださいました。




Breakout Session2



午後のセッションは2つの会場に別れて行われます。

どれも話を聞きたかったのですが、今回はこちらを聞くことにしました。

後日Videoやプレゼンの資料が公開されるようですので、今回聞けなかったものもチェックできるようです。いいですね。


Google Gadgets API - Sophia Brueckner




Sophia Bruecknerさんからは、GoogleGadgetsAPIについてです。


  • Gadgetsを利用して、先日名称変更されたiGoogleカスタマイズできる

  • ワールドカップの試合状況をリアルタイムに提供するガジェットが人気を博した

  • 世界中で10,000,000のリーチ

  • もっとも人気のガジェットであるWikipedia検索のガジェットは、14歳の少年が作成した。すごい!

  • ガジェット経由で自ページへのトラフィック増を期待できる

  • ガジェットはXMLで作成

  • ローカライズにも対応

  • Gadgets For your webpage - どこにでも設置できる!

  • Gadgets内のFlashアプリにてGadgetsのuserPref(ユーザデータ)を取得可能


Gadgetsの作成はとても簡単!らしいので、ガジェットコンテストもありますし何かつくってみたいですね。

面白いガジェットとして、マウスポインタを目で追うガジェットや、Pony(馬)の世話をするガジェット、金魚の世話をするガジェットが紹介されていました。

また、Googleでは、GMail、Calendarのガジェットがよく使われているようです(笑)



Google Desktop Gadgets - James Yum




James Yumさんからは、Google Desktop Gadgetsの紹介です。


  • ガジェットはユーザが求めている!(結構人気があるみたいです。知らなかった・・・)

  • ガジェットには、UniversalGadget(Webで動作。HTML+Javascript)と、DesktopGadget(XML+Javascript)がある

  • ヌードルタイマーのガジェット(日本製)や、バッテリー残量を教えてくれるガジェットが人気

  • SDKを利用すればガジェットを簡単に作成できる

  • AdvancedAPIs(DesktopGadgets特有のAPI)

  • CommunicationAPI - GoogleTalkの機能を利用しガジェット同士の通信を可能にする

  • QueryAPI - Googleデスクトップのインデックスから検索(非常に高速)

  • EventAPI - ブラウザを開いた等のイベントを扱うことが可能

  • 2007年はガジェットの年になるらしい

  • ActiveXを通して、WindowsAPIも扱うことが可能

  • VBScriptもサポート

  • デスクトップアプリケーションと同様のことが可能


デスクトップガジェットにはまったく興味がなかったのですが、なかなか面白そうです。挑戦してみようかしら。

公演中に、「たまたま」本社の友人がリストにいたので、実際にチェスのガジェットを披露してくれました。リクエストに答えてくれた友人がとても素敵でした。




Google AJAX API - 小俣 裕一




小俣 裕一さんからは、AJAX APIの紹介です。


  • AjaxAPIには、SearchAPIとFeedAPI(それにMapsAPI)がある

  • SearchAPIは、ローカル、Web、News、ブログ等のサーチを選択可能

  • FeedAPIは、SlideShowコントロール、Blogロール、TuneBarコントロールが使用可能

  • AjaxAPIsを用いると、簡単なUIも適用してくれる - すぐに利用可能


このAjax Feed APIは、弊社Webサイトのリニューアル時に実際に利用してみました。

ほんとに数行のJavascriptコードで実装できてとても簡単です。

簡単なUIも適用してくれるので、レイアウトにそれほどこだわらないときはすぐに利用が可能ですので非常に便利です。

ほかにもVideoやSlideShowも扱えるみたいですので、どんどん利用していきたいと思います。



Software Engineer in Google - 鵜飼 文敏




鵜飼 文敏さんからは、Software Engineer in Googleと題して、Google内での開発の様子を紹介してくださいました。GDD日本スペシャル講演です。

鵜飼さんは、本日でちょうど入社1年(6/1入社)になるとのこと


  • グーグルの開発センターは世界各地にあり、それぞれの場所でそれぞれのプロジェクトに参加し作業をしている(ローカライズだけをしているわけではない)

  • ソフトウェアの開発は、一人が全ての工程(設計~テスト)の責任を持つ

  • プロジェクトは非常にたくさんあり、ボトムアップで発生する

  • ひとつのプロジェクトは2~6名

  • イノベーション重視 - 早くどんどん作る!

  • オープンなコミュニケーション - IM, ML, Wiki ,Docs, Blog等

  • 最近はWikiより、リアルタイムに共同編集できるDocs & Spreadsheetsに移行しつつある

  • プロジェクト開始時にはDesignDocを作成

  • DesignDocには、背景・目的(Why?)、設計(How?)、メンバー(Who?)、セキュリティー・プライバシーについての考察、テスト・モニタプランなどが記載される

  • DesignDocは、他の人が見てどんなプロジェクトか分かる程度のもの。後から自分がみて理解するためにも重要

  • 主な言語は、C++, Java, Python, Javascript。最近は動画のためにActionScriptも。あとは独自言語のSawzall

  • あらゆるコードはひとつのリポジトリで管理 - 全エンジニアで共有

  • コードは他の人がレビュー

  • コーディングスタイル統一のためのリーダビリティレビュー

  • 偉い人ほどコードを書いている

  • パフォーマンスを重視。よりよいアルゴリズム、計測・最適化 - 遅いとつっこまれる

  • スケーラビリティは並列化

  • 「Testing on the Toilet」テストのうまいやり方を書いたビラをトイレ貼り付け - Unitテストは基本

  • 「遅いのは勝てない」「スケールは重要」 by エリック

  • Project,Idea,Bugの情報はデータベースにて共有

  • TechTalk - プロジェクトや自身の技術についてスピーチ

  • ユーザ情報、プライバシーデータは非共有。別サーバにて厳重管理

  • 仕事の評価は、同僚が評する - 一緒に仕事している人間が一番知っている(気が抜けない笑)

  • マーケティングにつては考えるな! - ユーザにとってどうなのか?使われるのか?人気があるかを重視

  • プロジェクトを社内で公開→人気があればLabsで公開→人気があればProductとして公開


本日一番参考になったのでは?と思える内容でした。

Googleでは、とにかく情報を公開することで、誰もがプロジェクトに自由に参加できるので、まさに社内でも玉石混交の淘汰が行われているわけですね。

各エンジニアが「これいい!」と思ったらどんどんプロジェクトを立ち上げられるわけで。

まさにインターネットの世界がGoogleの社内の世界なようです。




Reception Party






本日ラストは、レセプションパーティーです。

残念ながらGoogleの社員の方とはお話できなかったのですが、近くにいたBHA(B's Recorderを作っているところ)の方とお話ができてとても有意義な時間をすごすことができました。

当たり前ですが、Google社員の方は大人気でした!



Google Developer Day 2007 を終えて




冒頭でも書いたように、今回のGDDに参加して、とても刺激を受けました。

やはりこういう場に参加し、リアルな空気に触れることはとてもよいことですね!

今までGoogleというとある意味「神」のような存在に感じていましたが、とても身近で、フレンドリーな存在なんだと再認識しました。ものすごい存在には変わりありませんが・・・。



あとは、やっぱり英語は必須だなぁと痛感しました。僕はまったく英語ができないので、外国のエンジニアの方と話がしたいと思っても、なかなか踏み出せません。(同時通訳の方が咳き込んでしまい、何を言っていたのか分からない、なんてこともないでしょうし笑)



また、今回の東京出張により、普段はメールや電話でのやり取りだったお客様と直接お会いすることができました!

わざわざお会いいただき、ありがとうございました。

2007/03/31

WebObjectsで直接SQL実行


WebObjectsで、直接SQLを実行したい場合、よく目にするのは「EOUtilities.rawRowsForSQL」です。
今までずっとこいつを使っていたのですが、こいつでINSERTを実行したあとに、「ec.saveChanges()」をやると、以下のエラーが出るようです。


: Exception occurred while handling request:
java.lang.IllegalArgumentException: Array is empty
at com.webobjects.foundation.NSArray.objectAtIndex(NSArray.java:488)
at com.webobjects.jdbcadaptor.JDBCPlugIn.newPrimaryKeys(JDBCPlugIn.java:611)
:
:


なぜだかまったく分からず、色々調べてみると、

Are you expecting rows from your UPDATE statements? If not, why do you use rawRowsForSQL() in preference of evaluateExpression()?

どうやら、結果を求める場合はrawRowsForSQL()を使い、実行するだけの場合はevaluateExpression()を使うようです。



というわけで、以下のようにevaluateExpressionを使用するようにしました。

もちろんエラーはなくなりました。


EODatabaseContext dbContext = EOUtilities.databaseContextForModelNamed(ec, "model");
EOAdaptorContext adContext = dbContext.adaptorContext();
EOAdaptorChannel adCannel = (EOAdaptorChannel)adContext.channels().lastObject();
EOSQLExpressionFactory factory = new EOSQLExpressionFactory(adContext.adaptor());
EOSQLExpression expression = factory.expressionForString("sql");
adCannel.evaluateExpression(expression);

2007/03/24

logに残されるパスワードをフィルタリングする



Railsアプリを作成していて、動作の確認等で非常に重要なログファイルですが、このログには様々な情報が残されます。

例えばユーザ登録画面等で送信したパラメータもログに残されます。

ユーザ登録の際は、パスワードを入力したりしますので、パスワードがそのまま平文で残されるのはちょいとまずいものです。


Processing UserController#signup (for 192.168.0.25 at 2007-03-24 10:41:08) [POST]
Session ID: 42d8820cd16b8a672b86f737d8d6b4e8
Parameters: {"user"=>{"password_confirmation"=>"testpassword", "lastname"=>"Tarou", "firstname"=>"Test", "login"=>"tester", "password"=>"testpassword", "email"=>"test@test.com"}, "commit"=>"Signup", "action"=>"signup", "controller"=>"admin/user"}


そこで、以下のようにするとログに残されるパスワードをフィルタリングすることができます。

filter_parameter_logging(*filter_words) {|key, value| ...}


class ApplicationController < ActionController::Base
filter_parameter_logging "password"
end



すばらしい!


Processing UserController#signup (for 192.168.0.25 at 2007-03-24 10:43:50) [POST]
Session ID: 42d8820cd16b8a672b86f737d8d6b4e8
Parameters: {"user"=>{"password_confirmation"=>"[FILTERED]", "firstname"=>"Test", "lastname"=>"Tarou", "password"=>"[FILTERED]", "login"=>"tester2", "email"=>"test2@test.com"}, "commit"=>"Signup", "action"=>"signup", "controller"=>"admin/user"}

Filtering Sensitive Logs


2007/03/16

JavaMailでAuth認証とOutbound Port25 Blocking(OP25B)対策



JavaからMailを送信するのに、javax.mailを使って送信していたのですが、社内のサーバ構成を変更しているうちに送信できなくなってしまった。


javax.mail.SendFailedException: Sending failed;
nested exception is:
class javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
class javax.mail.SendFailedException: 553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)

at javax.mail.Transport.send0(Transport.java:218)
at javax.mail.Transport.send(Transport.java:80)
at SendMail.sendMail(SendMail.java:42)
...


どうやら認証が必要なようです。

今までは同じホストでアプリケーションが稼動していたので問題なかったようです。



というわけで、Auth認証、そしてOutbound Port25 Blocking(OP25B)対策をして対処しました。


import java.util.Properties;
import java.util.Date;
import javax.mail.Session;
import javax.mail.Message;
import javax.mail.Transport;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;

public class SendMail {
public void sendMail(
String sourceAdd,
String sourceName,
String descAdd,
String subject, String message,
String type) {
try {
Properties props = System.getProperties();
props.put("mail.smtp.host","mail.hoge.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
Authenticator auth = new MyAuthenticator();
Session session=Session.getDefaultInstance(props, auth);
MimeMessage mimeMessage=new MimeMessage(session);
mimeMessage.setFrom(new InternetAddress(sourceAdd, sourceName, "iso-2022-jp"));
mimeMessage.setRecipients(Message.RecipientType.TO, descAdd);
mimeMessage.setSubject(subject, "iso-2022-jp");
mimeMessage.setText(message, "iso-2022-jp");
mimeMessage.setHeader("Content-Type", type);
mimeMessage.setSentDate(new Date());
Transport.send(mimeMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
}

class MyAuthenticator extends Authenticator {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user" , "password");
}
}

2007/03/13

J-PHONE/3.0で、postがうまくいかない



携帯向けアプリを構築していて、特定の端末(おそらく)の場合だけ、post送信時、sessionが維持されない現象を確認。

post送信されるパラメータで、「"_session_id"=>"901cbb6b5a6d515a99a06373d20ba2f4?page=1"」というように、セッションIDのなかになぜか他のパラメータが混入する。

これでは当然、「そんなセッションありません」、ということになってsessionが維持できなくなります。



で、あれこれ試行錯誤した結果、どうやら、formのアクションで、自動でURLパラメータとしてsession_idを付与しているところが問題のよう。

formのアクションを直打ちして解決しました。



ちなみに自動でsession_idを付与してくれるのは、ActiveHeartのTransSidのお陰です。



参考:

RubyOnRails を使ってみる 【第 5 回】 ActiveHeart


2007/02/23

DNSサーバにて送信ドメイン認証SPF[Sender Policy Framework]レコードに対応



Ezwebへメールを送信した際に、以下のような返信メールを受け取った。(でもちゃんとメールは送信されていました・・・)

次のあて先へのメッセージはエラーのため送信できませんでした。

送信先メールアドレスが見つからないか、
送信先メールサーバの事由により送信できませんでした。
メールアドレスをご確認の上、再送信してください。

Each of the following recipients was rejected by a remote mail server.
--------------------------------------------------------------
Received-SPF: None (lsean.ezweb.ne.jp: 210.251.95.9 is neither permitted nor denied by domain of xxx.cc) client-ip=210.251.95.9;



調べてみるとなんだかSPFがどうのこうの・・・。

KDDI au: EZwebへメール送信する際の注意事項 > 送信ドメイン認証SPFレコードについて



というわけで、MTA/AntiSPAM/Sender ID を導入してみる - Pocketstudio.jp Linux Wikiを参考にDNSをSPF対応にしました。(Sender IDはまたの機会に・・・汗)


DNSの設定ファイルに以下のレコードを追加

                IN      TXT     "v=spf1 ip4:210.251.95.8/29 ~all"



check-auth@verifier.port25.comでのチェックもPASSした模様です。

※このアドレスに空メールを送信すると、チェック結果を返してくれます。

==========================================================
Summary of Results
==========================================================

mail-from check: pass
PRA check: pass
DomainKeys check: neutral (message not signed)


2007/02/16

ZABBIXでユーザーのMail設定はどこにある?



以前に、GIGAZINのフリーのサーバ、ネットワークなどの総合監視ソフト「ZABBIX」日本語版という記事をみて、「これはすごい」と思って早速社内サーバの監視に使用しています。

グラフ作成、各ノードの情報収集、異常検知、障害/復旧通知、詳細なアラート通知機能がZABBIX一本でできてしまうので非常に魅力的です。



障害等の通知はメールで通知したいのですが、なかなかその設定場所が発見できませんでした。

で、やっと設定場所を発見したのでメモしておきます。



設定[Configuration] > ユーザー[Users] で、設定するユーザ行/アクション列の「メディア」をクリック!

たったこれだけなのですが、この「メディア」という文字が通常のテキストと同じ黒文字だったため、クリックするという行為まで及ばなかったのです・・・「これはひどい」。



ユーザビリティって大切ですねぇ(笑)



参考:

ZABBIX Forums - Where to set an email address


2007/02/14

file_column and capistrano

Railsで画像ファイルをアップロードする場合、file_columnというプラグインがとても使えます。

このpluginは、画像のアップロード、保存、サムネイル作成といった面倒な処理を劇的に簡略化してくれます。


データベースにファイル名を保存するカラムを追加し、

add_column :entry, :image, :string


モデルで、file_column pluginを指定します。

class Entry < ActiveRecord::Base
file_column :image
end



この場合の保存先は、

public/[model_name]/[attribute_name]/[id]/[file_name].jpg

になります。


サムネイルを作成する場合は、次のようにします。

class Entry < ActiveRecord::Base
file_column :image,
:magick => {
:versions => {
:thumb => "50x50",
:midle => "100x100",
:large => "800x600"
}
}
end



この場合はそれぞれ、

public/[model_name]/[attribute_name]/[id]/[file_name].jpg

public/[model_name]/[attribute_name]/[id]/thumb/[file_name].jpg

public/[model_name]/[attribute_name]/[id]/midle/[file_name].jpg

public/[model_name]/[attribute_name]/[id]/large/[file_name].jpg

に保存されます。


ファイルをアップロードするには以下のhelperを使用します。

<%= file_column_field "entry", "image" %>


アップロードした画像を表示するには、以下のhelperを使用します。

<%= url_for_file_column "entry", "image" %>



サムネイルを表示するには、

<%= url_for_file_column "entry", "image", "thumb" %>




上記のように簡単に、非常に簡単に画像処理を扱えるようになるわけですが、capistranoでデプロイしている場合、画像の保存先がデフォルトのままだと、デプロイするたびに画像ファイルをコピーしなければなりません。

これではあんまりですが、ちゃんと回避策がありました。

file_columnのオプションに、root_pathというのがありまして、デフォルトの保存先を変更できます。

以下のように、capistranoが自動でリンクしてくれるsystemディレクトリに画像を保存するように指定すれば、いちいちコピーしなくてもよさそうです。

class Entry < ActiveRecord::Base
file_column :image,
:magick => {
:versions => {
:thumb => "50x50",
:midle => "100x100",
:large => "800x600"
}
},
:web_root => "system/files/",
:root_path => File.join(RAILS_ROOT, "public", "system", "files")
end




参考:

HowToUseFileColumn

2007/02/06

ExcelVBAでRoundUp、RoundDown


Excelでは、切り捨て、切り上げ、そして四捨五入といったことを、それぞれ、=ROUNDUP()、=ROUNDDOWN()、=ROUND()といった関数を利用して簡単にできます。

これらの関数は非常に便利で、よく利用します。


しかし、VBAでRoundUp(切り上げ)や、RoundDown(切り捨て)をする場合、VBAの標準関数にはこれらの関数はありません。


ですので、Excelのワークシート関数をVBAから呼び出して利用すると良いです。


Application.WorksheetFunction.RoundUp(y, -1)

注:ROUND(四捨五入)関数については、ワークシート関数とVBAとで、動作が異なるようです。

詳しくは、[XL2000]VBA の Round とワークシート関数 Round の違いをご覧下さい。


2007/01/31

増加するログファイルへの対処


Railsでは、ログファイルに絶えず情報が追加されていき、ものすごい勢いで肥大化していくわけですが、でかいログファイルは様々な面でよくありません。

ですので、定期的にログファイルのローテーションをするわけですが、主にlogrotateを使用する方法と、Loggerを使用する方法があるようです。

ただし、FastCGIをマルチで使用している場合は、各FastCGIプロセスにてLoggerインスタンスが存在し、同一ログをローテートしてしまうため、Loggerの使用は控えたほうが良いようです。

というわけで、logrotateを使用します。

/path/to/your/app/log/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
copytruncate
create 0666 daemon daemon
}

参考:

DeploymentTips in Ruby on Rails

2007/01/30

ActiveRecodStoreな場合のセッションの掃除


Railsでは、セッションが自動生成されるのですが、自動削除はしてくれません。

ですので、自分で掃除をしなければいけません。


session_cleaner.rb

class SessionCleaner
def self.remove_stale_sessions
CGI::Session::ActiveRecordStore::Session.destroy_all(['updated_on < ?', 1.days.ago])
end
end

上記クラスをlibあたりに保存し、cronで毎日自動実行させます。

0 0 * * * ruby /full/path/to/script/runner -e production "SessionCleaner.remove_stale_sessions"


参考:

Removing Stale Rails Sessions


2007/01/29

Basic認証の解除


Apacheにて、Basic認証で制限をかけているけど、特定の場所では制限を解除したい。

そんなときには、解除したいディレクトリの.htaccessにて、下記のようにすると実現できます。

Satisfy Any

more Satisfyディレクティブ

2007/01/25

Bドライブ





なぜフロッピーのAの次は、ハードディスクのCドライブにいくのだろうと、前々から気にっていたのですが、解決。

昔はフロッピーが二台あったからでした。

そういえば、昔のパソコンは確かにフロッピーが二台あった。懐かしいなぁ・・・





なぜ今のパソコンにはBドライブがないのか?という理由 - GIGAZINE


2007/01/23

jpmobile使用時のfunctionalテスト



[03/18追記]



下記は何れも既に対応されております。ご苦労様です。

詳しくはdara日記 [jpmobile]をご覧下さい。




dara日記 - jpmobile - A Rails plugin for Japanese mobile-phones



jpmobileというプラグインを使用すると、携帯向けのサイト構築が非常に楽になります。

jpmobileを使用すると、以下のことができるようになります。


  • 携帯電話の判別

  • 端末位置情報の取得

  • 端末製造番号、契約者番号等の取得

  • IPアドレスの検証(キャリアが公開しているIPアドレス帯域からのアクセスか判定)




ものすごく便利なプラグインなのですが、functionalテスト時にはまりました。

NoMethodError: undefined method `mobile?' for #

mobile?そんなメソッドありません。とのことです。

で、悩んだ挙句導き出した答えは、
ActionController::TestRequest.class_eval { include Jpmobile::CgiRequestExpansion}

を、テストクラスにて記述します。

きっと、テスト用のリクエストにjpmobileの機能をincludeするってことだと思います(w)。



それと、ソフトバンク携帯からの実機確認時に、なぜか携帯端末と判定されないという問題が発生。

こちらは、vendor/plugins/jpmobile/lib/jpmobile/cgi_request_expansion.rb のSoftbank端末判定部分を

when /^Softbank/

から、
when /^SoftBank/

に修正しました。




2007/01/19

ハードウェアの安全な取り外し


WindowsXPを使っていて、タスクトレイにある「ハードウェアの安全な取り外し」アイコンが消滅してしまったことはないでしょうか。

僕自身は経験がないのですが、知人にはちらほら出現しています。

調べてみると、どうやらWindowsのバグのようで、完全に復活させる方法はないようです・・・。

ですが、以下のコマンドを「ファイル名を指定して実行」から実行すると、ウィンドウが表示され、安全な取り外しを行うことができます。

rundll32 shell32.dll,Control_RunDLL hotplug.dll

いちいちコマンドを入力するのは面倒なので、ショートカットを作成し、コマンドを実行できるようにするのがよいです。

2007/01/18

DateHelperでid属性を使いたい



RailsにはDateHelperという便利なものがありまして、これを利用すると簡単に日付や時刻のセレクトボックスを作成できます。

ですが、なぜかidや、class等の属性が無視されてしまいます。(Rails 1.1.6にて。最新のものはどうなの?)

javascriptで操作したいときなど、idがないと困ります。

そんなときは、下記のようにするとよいです。(bad hack!)


<%= select_day(Date.today, :prefix => 'search[date][day]" id="day_field', :discard_type => true) %>


参考:

Rails Forum / Ruby on Rails Help and Discussion Forum / How to give an ID to an input when using select helpers?


javascriptでwindowを閉じる


javascriptでwindowを閉じるには

window.close();

なわけですが、window.open()で開かれたウィンドウ以外は警告が表示されます。

そこで、以下のようにすると警告が表示されずに閉じてしまいます。
var w = window.open('', '_top');
w.opener = window;
w.close();