javascript_include_tagstylesheets_link_tag:cache => trueオプションは、複数のassetsファイルを ひとつのファイルにまとめる事で、サーバへのリクエスト 数を減らすことができる機能です。

何度か実験してみたところ、生成されたキャッシュファイルを 削除して更新するためには、単純にファイルを削除するだけ ではだめで、APサーバのプロセスを再起動する必要があるようです。

このためには、./script/process/reaper -a graceful を使う必要があります。タイプするのが面倒なので、 Rakeタスクを作ってみました。

lib/tasks/cache.rake

   1  namespace :tmp do
   2    namespace :cache do
   3      desc 'Delete cached asset files'
   4      task :update do
   5        patterns = [
   6          'public/stylesheets/cached_*.css',
   7          'public/javascripts/cached_*.js']
   8        Dir.glob(patterns).each do |path|
   9          rm_rf path
  10          puts "deleted: #{path}"
  11        end
  12        `./script/process/reaper -a graceful 2>&1 > /dev/null`
  13        puts "script/process/reaper -a graceful"
  14      end
  15    end
  16  end

生成されるキャッシュファイルの名前を :cache => "cached_#{controller.controller_name}" と指定しているため、こんな感じになります。 デフォルトでは、all.cssall.jsとなりますので 適宜読みかえてください。

posted by Png genki on Sat 12 Jan 2008 at 23:17

比嘉さんからciteされたみたいなので、取り急ぎ新しい情報を吐き出しておこうと思います。

そろろろRailsについて本音を書いてみるか

後、デバッグの環境は、Javaに比べて貧弱だと思う。Railsでデバッグをする7つの方法を見てほしい。IDEでソースにブレークポイントを設定(ソースコードを書き換えるのではなく)して、ステップイン、ステップオーバー、メモリの状態を見たりなんてのに慣れているJavaから比べると、すっごく大変に見える。

喜ばしいことに、Rails 2.0ではruby-debugを使ったdebuggerが正式に採用されました。 これの使い方は非常に簡単です。

まずは、以下のようにブレークポイントをコード中に書き込みます。

   1  def some_method
   2    debugger # breakpoint
   3  end

続いて、Webサーバをデバッグモードで実行します。

   1  % ./script/server -u

これだけです。あとは、実際にブレークポイントを仕掛けた 場所が実行されるようにすれば、gdbライクなruby-debugの セッションが開始されます。 ruby-debugは、gdbと同じように、ステップ実行、ステップオーバー等の逐次実行を行うインターフェイスがあるので、 コードの動作を確認しながらデバッグを行うことができます。

gdbになれていない人には、irbコマンドを実行することで、 その場でirbを立ち上げることができます。これは非常に便利ですね。

参考までに、debuggerから実行できるコマンドのリストを 載せておきます。

   1  backtrace break catch cont delete display down eval exit finish frame help irb list method next p pp quit reload restart save script set step thread trace undisplay up var where

Have a good debugging life!

See Also

更新履歴

  • 2008/01/21 See Alsoに1点追加
posted by Png genki on Fri 11 Jan 2008 at 22:21

cache_fuやmemcachedを使うときに、cacheメソッドがオプションを 受け取ってくれないので不便だなと思っていたのですが、 EdgeRailsでは以下のようなパッチが当たっていて この問題は解決されているようです。

[PATCH] Rails have poor support to work with memcached

Let's assume we have a caching installation with Nginx used as a frontend. Nginx attempts to get page body by key from memcached. If it succeeds (meaning that the page is in memcached), Rails doesn't get control, making this schema extremely fast, up to 3K requests per second. In case memcached doesn't contain cached page by url as a key, Rails receive control, render page and cache it in memcached in order for the next request to be retrieved from memcached.

現状のリリースバージョンのコードでは、以下のようになっています。

vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb

   1  def cache(name = {}, &block)
   2    @controller.cache_erb_fragment(block, name)
   3  end

これが、EdgeRailsでは以下のように変更されています。

vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb

   1  def cache(name = {}, options = nil, &block)
   2    template_extension = first_render[/\.(\w+)$/, 1].to_sym
   3   
   4    case template_extension
   5    when :erb, :rhtml
   6      @controller.cache_erb_fragment(block, name, options)
   7    when :rjs
   8      @controller.cache_rjs_fragment(block, name, options)
   9    when :builder, :rxml
  10      @controller.cache_rxml_fragment(block, name, options)
  11    else
  12      # do a last ditch effort for those brave souls using
  13      # different template engines. This should give plugin
  14      # writters a simple hook.
  15      unless @controller.respond_to?("cache_#{template_extension}_fragment")
  16        raise "fragment caching not supported for #{template_extension} files."
  17      end
  18   
  19      @controller.send!("cache_#{template_extension}_fragment", block, name, options)
  20    end
  21  end

posted by Png genki on Fri 11 Jan 2008 at 05:48

RailsのCacheSweeperは非常に便利なのですが、 callbackからコントローラのインスタンス変数にアクセスできると もっと便利になる気がします。

ソースコードを読んでみたら、やっぱりみんなそう思うようで、 assignsメソッドが用意されていました。

   1  class PostsSweeper < ActionController::Caching::Sweeper
   2    observe Post
   3  
   4    def after_posts_rating
   5      expire_fragment "posts/show/#{assigns(:post).id}"
   6    end
   7  end

こんな風に書けます。これは便利。

posted by Png genki on Tue 8 Jan 2008 at 07:48

helpコマンドを使うと、script/consoleから非常に簡単に ドキュメントを参照することができます。 使い方は以下の通り。

   1  >> help CGI
   2  ------------------------------------------------------------- Class: CGI
   3       Wrapper around the CGIMethods that have been secluded to allow
   4       testing without an instantiated CGI object
   5  
   6  ------------------------------------------------------------------------
   7       TODO: document how this differs from stdlib CGI::Cookie
   8  
   9  ------------------------------------------------------------------------
  10       TODO: document how this differs from stdlib CGI::Cookie
  11  
  12  ------------------------------------------------------------------------
  13       Wrapper around the CGIMethods that have been secluded to allow
  14       testing without an instantiated CGI object
  15  
  16  ------------------------------------------------------------------------
  17       TODO: document how this differs from stdlib CGI::Cookie
  18  
  19  ------------------------------------------------------------------------
  20  (END)

引数としてクラスや文字列を渡すと、riと同じようにドキュメントを 照会することができます。ちょっと便利ですね。

posted by Png genki on Mon 7 Jan 2008 at 05:57

RJSテンプレートは、RubyコードからJavaScriptコードを生成 するための仕組みです。 今回は、RJSテンプレートの中でJavaScriptの条件分岐を 簡潔に記述するために、PrototypeHelperを拡張する方法を紹介します。

以下のようなファイルを作成して、config/initializersの下に 設置します(Rails 2.0以降の場合)

prototype_helper_ext.rb

   1  module ActionView
   2    module Helpers
   3      module PrototypeHelper
   4        class JavaScriptGenerator
   5          def if(condition, &block)
   6            page << "if(#{condition}){"
   7            block.call if block
   8            page << '}'
   9          end
  10  
  11          def elsif(condition, &block)
  12            page << "else if(#{condition}){"
  13            block.call if block
  14            page << '}'
  15          end
  16  
  17          def else(&block)
  18            page << "else{"
  19            block.call if block
  20            page << '}'
  21          end
  22        end
  23      end
  24    end
  25  end

これによって、こんな感じに条件分岐を記述できるようになります。

   1  render :update do |page|
   2    page.if "$$('#posts .post').length == 0" do
   3      page.remove 'posts'
   4    end
   5  end

最初から用意されててもいい気がする。

posted by Png genki on Sat 5 Jan 2008 at 16:49

You can see also http://blog.s21g.com/articles/212, the article written about the same theme for comparison, if you are familiar to Japanese.

1. p/pp

This is a very popular method used not only in Rails but also in other debugging. In Rails this method should be used on web server which is in the states of foreground process.

   1   $ ./script/server

If you are familiar with p/pp, it should be simple and easy.

2. logger.debug

For logger.debug, the following example will explain fully.

   1  logger.debug "something interesting information"

Calling logger.debug, you can create a log file of log/$RAILS_ENV.log such as log/development.log.

By configuring the output file to:

   1  $ tail -f log/development.log

you can check the debug output log in the same manner as in p/pp debugging. Furthermore, as the result is output in a log-file format, you can refer it later on.

3. script/console

script/console comes in handy when you check the DB contents during the operation. Executing "script/console" command, irb launches after confirming Rails environment. You can change DB as you like by using ActiveRecord, such as find, create and destroy_all.This is very tactful feature.

4. script/breakpointer

As previously described, although script/console comes in very handy and tactful, it can not check session status during the action. In that case, you can use "script/breakpointer" for it.

   1  $ ./script/breakpointer

Please make sure to launch a breakpointer initially. Then locate a "breakpoint" to the position where you want to check the status.

   1  class FooController < ApplicationController
   2    def bar
   3      # something
   4      breakpoint
   5      # something
   6    end

Then you execute bar action through brower access and check and manupulate the necessary information after the launch of irb at the set breakpointer.

5. better rails debugger

script/breakpointer is very useful but it has a weak point as it cannot operate step execution. We understand you rarely experience the need for step execution, however, it's better to have a method than nothing. The ruby-debug Gem, informed by yugui in the last Rails meeting, will meet the need. First of all, make sure to install ruby-debug in advance.

   1  # gem install ruby-debug

Then, add a breakpoint.

   1  class FooController < ApplicationController
   2    def bar
   3      # something
   4      debugger
   5      # something
   6    end

After launching Web server such as Webrick or Mongrel on foreground, which is used in p/pp debugging, you make an access to execute targeted code through the browser. Then something similer to debug.rb launches in Web server process. Now you can start debuggin in the same manner as you do with general ruby script.

6. test/autotest

In Ruby on Rails, test framework is ready to use by default. Generally, specification is designed after writing a test code in test operation development. However, you can write a test code for verification of desired behavior and also utilize it for debugging. It takes time to operate every test by using "rake" command, I recommend to use autotest in ZenTest.This autotest operates only related tests for modified files, and can provide quicker response than using "rake" command. If you use a redgreen as a combination, the smooth operation will please you while debuggin.

7. tail -f log/development.log&; autotest

Lastly, let me intriduce my current method.I launch a separate terminal other than for development, and operate following command in RAILS_ROOT.

   1  $ tail -f log/development.log&; autotest

This arrangement enables to display the autotest output in editing program and test code and the logger output when there is an access from the browser. Basically, those two runs asynchronously, you can fully use one terminal.

posted by Png genki on Fri 4 Jan 2008 at 05:17
1st Tue

HAPPY NEW YEAR!

   1  class Happy
   2    def year!
   3      sleep 4.hours
   4    end
   5  end
   6  
   7  Happy.new.year!

I wish you a happy new year.

posted by Png genki on Tue 1 Jan 2008 at 00:00