Railsのroutes.rbでNamed Routeを利用するときに、 メソッド名の競合などで通常は使えない名前をどうしても 利用したい場合、以下のように記述することで利用できます。

config/routes.rb

   1  map.send :method_missing, :touch, 'foo/:id/touch', :action => 'touch'

メソッドがすでに定義されているため、method_missing が呼ばれなくなっている状態を無理やり回避しています。

posted by Png genki on Mon 26 Nov 2007 at 15:02

Railsのプラグインは、簡単に作れるせいか、おかしな、 というか、随分てきとうな名前のものが多いのですが、最近は 一時期流行していたacts_as_xxxable系のプラグインに代わり、 xxx_fuという名前のプラグインが増えてきました。

timezone_fu

  • Timezone conversion with TZInfo as easy as has_timezone :fields => [ :start_datetime, :end_datetime].
  • 美しい世界地図が印象的

enum_fu

  • Make an integer field as an enum typed one

resource_fu

  • A collection of hacks that make nested and polymorphic resources less painful.

Bundle-fu

  • CSS/JS asset bundling in 10 seconds or less!
  • Rails-2.0 Readyだ!

mimetype-fu

  • Get the content type / mime type of a file. Great to use with attachment_fu or to validate Flash uploads.

Attachment Fu

  • Rewrite of acts_as_attachment
  • Amazon S3も使える

Permalink Fu

  • Create permalinks from attributes

BackgroundFu

  • Threadを使って時間がかかる処理を行う

さて、次に流行するのはどんな名前でしょう。

更新履歴

  • 2007/12/11 BackgroundFuを追加
posted by Png genki on Mon 26 Nov 2007 at 05:43

記事の引越しから漏れていたのでサルベージ。

zsh用のscript/generateおよびscript/destroyの補完関数です。 以下のスクリプトを.zshrcなどに書いておけば、 ./script/generateに続けてTABキーを押す事で generatorの入力を補完できます。

~/.zshrc

   1  _generate () {
   2    if [ ! -f .generators ]; then
   3      ./script/generate --help | grep '^  [^ ]*: ' | sed 's/[^:]*:/compadd/' | sed 's/\,//g' > .generators
   4    fi
   5    `cat .generators`
   6  }
   7  
   8  compdef _generate generate
   9  compdef _generate destroy

RubyGems、Plugin、BuildInの3種類のgeneratorを検出して補完します。 検出動作が重いので、カレントディレクトリにキャッシュファイルを作成して 2度目以降の補完を高速化しています。 generatorを追加した場合など、キャッシュを無効化したい場合は

   1  $ rm .generators

でキャッシュファイルを削除してください。

補完が重くても余計なファイルが生成されるよりはマシ、 という場合はこちらをどうぞ。

   1  _generate () {
   2    `./script/generate --help | grep '^  [^ ]*: ' | sed 's/[^:]*:/compadd/' | sed 's/\,//g'`
   3  }
   4  
   5  compdef _generate generate
   6  compdef _generate destroy

誰かが作らないかなあ、と思って待っていたのですが、 なかなか出て来ないので自分で作りました。 もっと良いものがあったら教えていただけると嬉しいです。

posted by Png genki on Mon 26 Nov 2007 at 05:05

ORF 2007 で地下展の話を聞いて興味深かったので、 日本科学未来館に行ってきました。

ticket

ボストーク湖 の展示が興味深かったです。 ほかにもいくつか面白いキーワードを採取できました。

それから、お土産店で蛍石と方解石をGet。

蛍石(左)と方解石(右)

rock

どちらの鉱石も、レンダリングアルゴリズムを考える上では、 興味深い光学特性を持っています。

posted by Png genki on Mon 26 Nov 2007 at 04:31

記事の引越しから漏れていたのでサルベージ。

Generatorプラグインの作り方をメモしておきます。

まずはプラグインの雛形を作ります。

   1  $ ./script/generate plugin foo

次にGeneratorプラグインに必要なディレクトリを用意。

   1  $ mkdir -p vendor/plugins/foo/generators/foo/templates

FooGeneratorクラスの定義ファイルを作成

vendor/plugins/foo/generators/foo/foo_generator.rb

   1  class FooGenerator < Rails::Generator::NamedBase
   2    def initialize(runtime_args, runtime_options = {})
   3      super
   4      ~ 引数・オプションの解釈と初期化 ~
   5    end
   6  
   7    def manifest
   8      record do |m|
   9        ~ マニフェスト ~
  10      end
  11    end
  12  end

マニフェストの書き方は この辺 が参考になります。基底クラスは、Rails::Generator::Baseの派生クラスなら何でもOKです。

続いて、マニフェストから参照するテンプレートファイルをtemplatesディレクトリの中に作ります。テンプレートファイルはERbテンプレートなので、Generatorクラスのコンテクストでrhtmlを書くような感じで記述できます。

以上で完了。Generatorを使うときは以下の通り。

   1  $ ./script/generate foo 

マニフェストの書式を以下にまとめておきます。

m.class_collisions( *class_names)

生成するクラス名の衝突を検出します。 Generatorで生成する予定のクラス名をすべて列記しておきましょう。

m.directory(relative_path)

RAILS_ROOTからの相対パスで、指定したディレクトリを利用する事を 宣言します。

m.template(relative_source, relative_destination, template_options = {})

Generatorが生成するファイルを宣言します。relative_sourceは、templatesディレクトリからの相対パスでERbテンプレートを指定します。relative_destinationには生成されるファイルの場所をRAILS_ROOTからの相対パスで記述します。

template_optionsには、:assigns => {:foo => some_thing} のような感じで、ERbテンプレートから参照可能な値を設定する事ができます。

m.readme( *relative_sources)

helpドキュメントを指定します。指定したファイル群は単純に連続出力されます。

m.migration_template(relative_source, relative_destination, template_options = {})

migrationファイルの生成を宣言します。migrationファイルは、ファイル名の先頭に005_のようなプレフィックスが付くので、専用のメソッドが用意されています。

relative_destinationは、migrationファイルを配置するディレクトリを、RAILS_ROOTからの相対パスで指定します。生成するファイル名は、template_options[:migration_file_name] で明示的に指定するか、さもなくばGeneratorの引数から自動的に決定されます。

そのほかの挙動はm.templateと同じです。 

m.dependency(generator_name, args, runtime_options = {})

Generatorの依存関係を宣言します。これによってメタジェネレータを記述する事も可能です。素晴らしいですね。

m.file(relative_source, relative_destination, file_options = {}) {|sf| ...}

ファイルのコピーを宣言します。relative_sourcerelative_destination はそれぞれRAILS_ROOTからの相対パスです。 file_optionsには、:chmod, :shebang, :collisionを指定します。 詳細な挙動については こちら を参照のこと。

ブロック引数は、relative_sourceで指定したファイルが何らかのテンプレートファイルであるときに、テンプレートを展開する処理を記述します。そうでない場合は省略可能です。

より詳細な情報が必要な場合は、 Rails::Generator::Commands::Createクラスのドキュメント 及び Createクラスの基底クラスであるRails::Generator::Commands::Baseのドキュメント をご覧ください。

更新履歴

  • 2006/08/10 マニフェストの書き方を最後の方にまとめておきました。
  • 2007/11/22 記事の移行からもれていたのでサルベージ
posted by Png genki on Thu 22 Nov 2007 at 05:10

記事の引越しから漏れていたのでサルベージ。

Ruby on Railsを使ってある程度大きめのアプリケーションを作るようになると、ごく稀に「Lost connection to MySQL server during query」というエラーが発生するようになる事があります。

この問題については、yuguiさんの記事 「Lost connection to MySQL server during query」 に詳しいです。

結局のところ、はっきりとした解決策も見つからず、ごく稀なので放置気味になっていたのですが、先日解決策を見つけたので改めて紹介します。

解決策:

mysql_retry_lost_connectionというrubygemを使うことで、コネクションのLostが発生した場合に、自動的に再接続を試みるようにActiveRecordの挙動を修正することが出来ます。

詳細はこのGemの作者のTylerさんの記事 「Saying goodbye to lost connections in Rails」で説明されています。

使い方:

# sudo gem install mysql_retry_lost_connection

を行い、config/environment.rbの中でrequire 'mysql_retry_lost_connection'をすればOK。 rails 2日ほど使ってみたところ、このGemを導入してから一度もLostConnectionのエラーが発生しなくなりました。このGemが効果を表さない場合もあると思いますが、Lost Connectionでお悩みの方には朗報ではないかと思います。

See Also

posted by Png genki on Wed 21 Nov 2007 at 13:30

記事の引越しから漏れていたのでサルベージ。

RubyInsideで紹介されていたUsing Omnigraffle to visualise Rails model associationsに触発されて、 Model同士の関係をグラフで表示するプラグインを作ってみました。

こんな感じのグラフを表示します。

使い方は、まずプラグインをインストールします。

$ ./script/plugin install http://svn.labs.drecom.jp/rails/plugins/trunk/model_graph
このプラグインはControllerジェネレータになっているので、次のように ModelGraphを表示するControllerを生成します。
$ ./script/generate model_graph
これによってModelGraphControllerが生成されるので、あとは'/model_graph'にアクセスすれば、上図のようなグラフが表示されます。もちろんGraphVizに依存しているので、事前にインストールしておく必要があります。

オリジナルの実装に加えて、app/models以外の場所に存在するすべてのModelの関係を表せるように改良してあります。

デフォルトのURLマッピングを削除している場合は、routes.rbにmodel_graphコントローラのindexアクションにマップするURLの記述を追加してください。

map.connect 'model_graph', :controller => 'model_graph'
ジェネレータプラグインなので、不要になったら
$ ./script/destroy model_graph
を実行すれば削除できます。

デフォルトではPNG形式の画像が出力されますが、'/model_graph?format=svg'のようにフォーマットを指定する事で、GraphVizがサポートするpng、gif、jpeg、svgの4種類の形式で出力する事ができます。

posted by Png genki on Wed 21 Nov 2007 at 13:16

記事の引越しから漏れていたのでサルベージ。

secondlifeさんの記事 に反応して後で書こうかなあと思っていたら、大分時間がたってしまいましたが、めげずに書いてみます。

1. p/pp
こちらはRailsに限らず良く使われている方法ですが、RailsではWebサーバをフォアグラウンドプロセスとして立ち上げた状態で使う感じになります。
   1  $ ./script/server
p/ppに慣れている人にはわかりやすくて良いと思います。

2. logger.debug
さて、続いてlogger.debugを使う方法です。
   1  logger.debug "something interesting information"
p/ppの代わりにlogger.debugを呼ぶ事で、結果がlog/development.logなどのlog/$RAILS_ENV.logファイルに書き出されます。 書き出されたファイルを、
   1  $ tail -f log/development.log
しておくと、p/ppでデバッグする時と同じような感じでデバッグ出力を見る事が出来ます。また、出力結果はlogファイルとして残っているので、後で参照する事もできます。
3. script/console
script/consoleは、実行時にデータベースの中身がどうなっているかを知りたい時に非常に便利です。script/consoleコマンドを実行すると、Railsの環境を読み込んだ状態でirbが立ち上がるので、ActiveRecordを使ってfindしたりcreateしたりdestroy_allしたり、好きなようにDBをいじる事ができます。本当に素晴らしい機能ですね。

4. script/breakpointer
script/consoleはとても素晴らしいのですが、アクション実行中のsessionの状態を調べたりするのには使えません。そんな時は、script/breakpointerを使う事ができます。
   1  $ ./script/breakpointer
まず、あらかじめbreakpointerを立ち上げておきます。続いて、状態を確認したい場所にbreakpointを仕込みます。
   1  class FooController &lt; ApplicationController
   2    def bar
   3      # something
   4      breakpoint
   5      # something
   6    end
あとは、ブラウザからアクセスしてbarアクションを実行すると、待ち受けていたbreakpointerでirbが立ち上がるので、必要な情報を自由に閲覧・操作する事ができます。
5. better rails debugger
script/breakpointerはとても便利ですが、ステップ実行が出来ないという問題があります。 実際にステップ実行がどうしても必要という場面はあまり無いのですが、あればあったほうが便利ですね。そんな時は、ruby-debugというGemを使います。 これは前回のRails勉強会のときにyuguiさんから教えていただいた方法なのですが、まずはruby-debugをインストールします。

   1  # gem install ruby-debug
次に、ブレークポイントを仕込みます。
   1  class FooController &lt; ApplicationController
   2    def bar
   3      # something
   4      debugger
   5      # something
   6    end
あとは、p/ppデバッグをするときのようにWebrickやMongrel等のWebサーバをフォアグラウンドで立ち上げ、目的のコードが実行されるようにブラウザからアクセスします。 すると、Webサーバのプロセス上でdebug.rb(と似たような感じのもの)が立ち上がるので、通常のrubyスクリプトを デバッグする時と同じ要領でデバッグを行う事ができます。
6. test/autotest
Ruby on Railsでは、テスト用のフレームワークがはじめから使える状態になっています。 テスト駆動開発では、テストを書いてから実装を書きますが、適当な動作検証用のコードをテストとして書くことで、デバッグに使う事もできます。この際、毎回テストをrakeコマンドから実行するのは時間が掛かるので、ZenTestのautotestを使うのがお勧めです。 autotestを使うと、編集されたファイルに関連するテストだけを実行してくれるので、rakeコマンドを実行するよりも軽快なレスポンスが得られます。さらにredgreenを併用すると気分良くデバッグを行う事ができるのでお勧め。
7. tail -f log/development.log&; autotest

最後に、僕が今使っている方法を紹介します。 開発用とは別に一つターミナルを立ち上げて、RAILS_ROOTで以下のコマンドを実行。
   1  $ tail -f log/development.log&amp;; autotest
こうしておくと、プログラムやテストコードを編集した時はautotestの出力が表示され、ブラウザからアクセスした時にはロガーの出力が表示されます。 基本的に両者が同時に行われる事は無いので、一つのターミナルを有効利用する事ができておすすめ。

というわけで、Railsでデバッグを行う方法の紹介でした。

posted by Png genki on Wed 21 Nov 2007 at 12:38

記事の引越しから漏れていたのでサルベージ。

RubyGems パッケージの作り方 - rubyforge 登録まで

僕はまだRubyForgeにGemを登録した事がないので、secondlifeさんの記事はとても参考になりました。蛇足感もありますが、多様性は善という事で、HoeというGemを使ったもう一つのRubyGemsパッケージの作り方を紹介します。

Hoeは、Seattle.rb Projects による一連のプロジェクトの中の一つで、やはりnewgemと同じようにRubyGemsの作成を簡単にしてくれるGemです。

Hoeを使ってGemを作る流れは、

  1. sowコマンドでGemの雛形を生成
  2. 雛形を元にGemを作成

という感じで、非常に簡単です。具体的に簡単なGemを作る方法を紹介します。

まずはHoeをインストールしましょう。

# gem install hoe --include-dependencies

そしてGemの雛形を生成します。

   1  $ sow sample
   2  creating project sample
   3  ... done, now go fix all occurances of 'FIX'
   4  
   5    sample/Rakefile:9:  # p.summary = 'FIX'
   6    sample/README.txt:2:    by FIX
   7    sample/README.txt:3:    FIX
   8    sample/README.txt:7:FIX
   9    sample/README.txt:11:* FIX
  10    sample/README.txt:15:    FIX
  11    sample/README.txt:19:+ FIX
  12    sample/README.txt:23:+ FIX
  13    sample/README.txt:29:Copyright (c) 2006 FIX

とりあえずこのFIXというところをカスタマイズすればOKという親切ぶりです。 そしてさらに、次のようなRakeタスクが生成されます。

   1  $ rake -T
   2  (in /home/takiuchi/sample)
   3  rake announce         # Generate email announcement file and post to rubyforge.
   4  rake audit            # Run ZenTest against the package
   5  rake check_manifest   # Verify the manifest
   6  rake clean            # Clean up all the extras
   7  rake clobber_docs     # Remove rdoc products
   8  rake clobber_package  # Remove package products
   9  rake debug_gem        # Show information about the gem.
  10  rake default          # Run the default tasks
  11  rake docs             # Build the docs HTML Files
  12  rake email            # Generate email announcement file.
  13  rake install          # Install the package. Uses PREFIX and RUBYLIB
  14  rake install_gem      # Install the package as a gem
  15  rake multi            # Run the test suite using multiruby
  16  rake package          # Build all the packages
  17  rake post_news        # Post announcement to rubyforge.
  18  rake publish_docs     # Publish RDoc to RubyForge
  19  rake redocs           # Force a rebuild of the RDOC files
  20  rake release          # Package and upload the release to rubyforge.
  21  rake repackage        # Force a rebuild of the package files
  22  rake ridocs           # Generate ri locally for testing
  23  rake test             # Run the test suite. Use FILTER to add to the command line.
  24  rake uninstall        # Uninstall the package.

なんとも魅力的な名前のタスク達ではないでしょうか。 rakeコマンドを打つだけでRubyForge上でのいろんな作業が出来てしまいそうです。

そのほか細かいところは同じなので、secondlifeさんの記事をご参照ください。

posted by Png genki on Wed 21 Nov 2007 at 12:14

LiveConsole

昔、Rails勉強会の懇親会で yuguiさん と話した、走り続けるプログラムの事を思い出した。

  • 起動や停止するという概念が無いプログラム
  • 自己複製による並列処理
  • 蓄積したバグによる老化と死、世代交代

そして、それを記述するための言語。

継承、遺伝、進化。

posted by Png genki on Wed 21 Nov 2007 at 11:25