Showing posts with label Rails. Show all posts
Showing posts with label Rails. Show all posts

Sunday, February 17, 2008

rescue_from() and Proc#bind()

Rails 2.0 の新機能に rescue_from(exception_class) という地味なやつがあります。いままでは、 ApplicationController などで rescue_action などをオーバライドして引数に与えられる exception を case ... when で処理するというわかりやすいけど、ダサイ方法で対応してきました。rescue_from を使うとこんな感じに書けます。


class UnauthorizedError < RuntimeError; end

class ApplicationController < ActionController::Base
...
before_fiter :login_required
def login_required
raise UnauthorizedError
end

rescue_from UnauthorizedError do
redirect_to login_path(:return_to => request.request_uri)
end
end


before_filter などにブロックを与える場合、そのブロックの self はそのコントローラのクラスなので、ブロックパラメータ controller を使うか、上記のようにインスタンスメソッドのシンボルを与える方法を使います。 ApplicationController で login_required のようなフィルタを追加した場合、かならず skip_filter したいケースがあるのでこの場合はいいんですけど、 before_fiter :foo; def :foo; ... end と冗長な書き方がウザイときもあります。

それと比べて、 rescue_from のブロックの中身はなぜかインスタンスメソッドと同じように書けます。Ruby 標準にはそんな機能はない思ってたのにと調べたら、秘密は ActiveSupport の Proc#bind() でした。

以上。

Saturday, January 5, 2008

"Advanced Rails Recipes" beta book updated with 25 more recipes!

Advanced Rails Recipesにひと月足らずで25の新しいレシピが追加された。
先日の記事What I'v just discovered in Advanced Rails Recipesでは、あんまり面白くなかったと書いたけれど、今回追加されたレシピには興味を惹く引くものが多かった。
追加されたレシピのタイトルは、著者の Mike Clark のブログで参照してください。

また、前回と同様に簡単なメモを...

Skinny Controller, Fat Model


モデルが汚くなるのを犠牲にしてもコントローラをシンブルにすることを自分と同僚で推奨していたが、そのことが "skinny controller, fat model" (もとネタは Jamis Back のブログらしい) という言葉で、いくつかのレシピで言及されているのを見て、「やっぱりそれでよかったんだ」と思った。

caching up with big guys


cache_fu は ActiveRecord::Base.find の結果をキャッシュする。
acts_as_cached には :include => :tags や :ttl => 5.minutes がある。

returning true do
...
end

というコードがあり、 active support に returning というメソッドがあることを知った。

returning [] do |value|
value << "foo"
value << "bar"
end

という使い方もできる。
activesupport/lib/active_support/core_ext/object/misc.rb を見たら with_options もあったことを思い出した。
しかし、こういうよく知られていない、または自前のメソッドを使うとコードがわかりにくくなる。

Creating meaningful relationships through proxies



group.rb:
has_many :users

user.rb:
class User < ActiveRecord::Base
def self.find_men
self.find(:all, :conditions => "sex = 'male'")
end
end

で、 association proxy からも group.users.find_men として利用できることを知った。考えてみれば当然かもしれないが気づかなかった。

Decouple your javascript with Low Pro


lowpro.jsのEvent.createBehavior, Event.addBehavior を使えば javascript をスッキリ書けるかも

Dynamically Updating Cached pages


動的要素のあるページを page cache にしたときにそのダイナミックな部分を ajax で更新するようにはしたことがあるが、部分だけタイムラグが出てしまうが、この方法だと session とは別の cookie に javascript だけでダイナミック部分を補完できる情報を(i.e:ユーザー名)入れておけば javascript で cookie の中身を使って static page の補完ができるというアイデア。

Handling Multiple Models In One Form


Project has_many :tasks などのときに、Project#new_tasks= でコントローラを小さくする手法。この手法も良く使う。

Responding To Remote Capistrano Prompts


Capistrano でリモートサーバーの script/console セッションを操作する方法が書いてある。試してみよう。

Taking Advantage of Master/Slave Databases


リプリケーションしたDBへのクエリを master/slave で自動で振り分ける
masochism plugin の紹介。使えるかもしれない。

Testing HTML Validity


HTML test plugin の紹介。
たぶん常に有効になっているとウザイので、 rake html_validity test のようにして実行したときだけ有効になるようにすると良いかもしれない。

Thursday, December 27, 2007

A small pitfall on Mac with Capistrano's deploy:web:disable task

To test a deployment process of a rails application at my local machine, a Mac OS X Leopard, I set up virtual host with Apache + reverse proxy + mongrel. When I tried to do "cap deploy:web:disable", I fell in to a pitfall, a Mac OS X local issue. The apache constantly respond "403 forbidden" for every URL under the virtual host.

The things is...

  1. Capistrano uses "/system/maintenance.html" for the path to the maintenance page (by the default)

  2. And if you use Apache mod_rewrite, the setting about maintenance.html may look like this:

    RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
    RewriteCond %{SCRIPT_FILENAME} !maintenance.html
    RewriteRule ^.*$ /system/maintenance.html [L]

  3. But, "RewriteRule" searchs the root of the file-system for "/system/maintenance.html" first (See description about "URL-path" of RewriteRule)

  4. Yes, there is the directory "/System" on Mac OS X, and HFS+ doesn't matter case of filename

  5. "/System" aren't accessible with httpd except you are mad

  6. So, you get "403 Forbidden"


A alternative of the rewrite rule is:

RewriteRule ^.*$ %{DOCUMENT_ROOT}/system/maintenance.html [L]

It works on Mac OS X (and other systems as well I think).

Sunday, December 9, 2007

What I'v just discovered in Advanced Rails Recipes

Advanced Rails Recipes のβブック(pdf) がリリースされたので早速購入して、ザクっと目を通してみました。

一年以上 Rails のアプリケーションを仕事で作っているので、前作(といっても著者は違うけど) Rails Recipes を読んだときほどの発見はなかったけれど、細かい発見がいくつか。ほんのメモ程度なので詳細を知りたい人は本を買ってやってください。

Recipe 17 - Accessin’ Helpers



$ script/console
Loading development environment.
>> helper.human_size 333232323
=> "317.8 MB"


From Recipe 32 - Running Multi-Stage Deployments



set(:deploy_to) { "/path/to/#{application}/#{stage}" }

deploy_to が評価されるときにブロックが実行される。

Recipe 12 - Simplifying Controllers With a Presenter


1つのフォームとアクションで複数のモデルを扱うときのパターン。
普通の ruby のクラスを使って user_name のようなメソッドを method_missing で send("user").send("name") のようにデリゲーションする この method_missing の使い方だけでもいろいろ使えそうだ。
Jay Fields Thoughts : Rails : Presenter Patternが元ネタですね。

Recipe 25 - Enabling Remote Testing


ssh -R オプションによるポートフォワーディングで、開発マシンで実行しているアプリケーションをプロダクションサーバーから参照できるようにする。なるほど。

Friday, November 23, 2007

Testing ANY helper in a functional test

Recipe #44 - "Write Tests for Your Helpers" in the book "Rails recipes" instructs us doing this by including helper modules in subclasses of Test::Unit::TestCase. However it wouldn't work if a helper you want to test is implemented with _erbout for example. I have just faced this issue last week, then my colleague suggested me like that "Don't you render it in a view?" (in Japanese). Yes, in a view biding, every helpers must be work correctly.

The solution is like following code:

test/units/foo_helper_test.rb:
...

class FooTestController < ActionController::Base
...
def index
render :inline => <<-INLINE
<% foo do %>
<%= ... %>
<% end %>
INLINE
end

end

class FooHelperTest < Test::Unit::TestCase
def setup
@controller = FooTestController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end

def test_foo
get :index
# do assert_select or whatever you like, to check rendering result of the helper.
end
end

Sunday, November 11, 2007

Rails on Leopard

I had little trouble when I got Leopard ready for my daily task, coding rails applications. I share my notes with hope you think them useful.

Leopard で rails の開発作業ができるまでに多少トラブったので、そのメモを公開します。

http://tagnote.yakitara.com/notes/192