Rails2.0.2を使ってみる

form_forのことなどを調べているうちに、Rails1.1.6、1.2.6、そして2.0.2とバージョンアップを重ねるごとに、便利なヘルパメソッドもますます充実していることに気付いた。(sum、label、div_for、content_tag_for...)そろそろRails2.0.2環境も触っておかないと...という思いになった。そこで、1アクションで複数のモデルを同時に保存するこの日記のサンプルを、試しにRails2.0.2環境で動かしてみることに。

Railsのアップデート

  • まずは、Railsのアップデート。gemを使って以下のようにやってみた。gemの使い方さえ分かれば簡単だ。*1
# Rubyパッケージ管理ソフトgemのアップデート
$ sudo gem update --system

# gemのバージョン確認
$ gem -v
1.0.1

# gemでインストール済みのRailsのバージョン確認
$ gem list rails

 *** LOCAL GEMS ***

rails (1.2.6, 1.2.3)

# Railsを最新版にアップデート
$ sudo gem update rails
Updating installed gems...
Attempting remote update of rails
Successfully installed rails-2.0.2
1 gem installed
Gems updated: rails

# ついでにRails-1.1.6もインストールしておく(今までLocomotive環境で使っていたバージョンであるため)
$ gem install rails -v 1.1.6
Successfully installed rails-1.1.6
1 gem installed

# gemでインストール済みのRailsのバージョンをもう一度確認
$ gem list rails

 *** LOCAL GEMS ***

rails (2.0.2, 1.2.6, 1.2.3, 1.1.6)

# Railsのアップデート完了!
  • その他、gemの使い方いろいろ
# gemでインストール可能なrailsバージョンを確認(railsで始まるソフトウェアのバージョンを確認)
$ gem list rails -r

# gemのヘルプ
$ gem help

# gemのコマンドヘルプ
$ gem help commnad

# gemコマンドinstallのヘルプ
$ gem install -h

Railsのバージョンを使い分ける

今までRailsを2.0.2にアップデートしてしまうと、過去のプロジェクトも含めて、常にその環境で利用するしかないと思い込んでいたが、実はそうではないんですね。簡単に、異なるバージョンのRailsプロジェクトを同時進行出来る。(Rails2.0とRails1.2を共存させる方法 - moroさんの日記)素晴らしい!

# Railsバージョン2.0.2のtestプロジェクトを作る。
$ rails test202
# バージョン指定しなければ最新の2.0.2環境に。
# Railsバージョン1.2.6のtestプロジェクトを作る。
$ rails _1.2.6_ test126
# 以降、このtest126プロジェクトはRails1.2.6環境で稼働する。
# Railsバージョン1.1.6のtestプロジェクトを作る。
$ rails _1.1.6_ test116
# 以降、このtest116プロジェクトはRails1.1.6環境で稼働する。
  • ちなみに、1.1.6環境を起動したとき、config/boot.rbの28行目でエラーが発生した。
  • 1.2.6環境の対応するコード部分をコピーして以下のように修正すると正常に起動するようになった。
config/boot.rb
@@ -28,1 +28,1 @@
 - require_gem "rails", "=#{version}"
 + gem "rails", "=#{rails_gem.version.version}"
(-行が修正前、+行が修正後)

Rails2.0.2プロジェクトの開始

それでは準備が整ったので、Rails1.1.6の知識しか持たない自分が、Rails1.2.6環境で試していた、1アクション多明細保存プロジェクト(プロジェクト名: test_slip126)をRails2.0.2環境へ移植してみる。(databaseはsqlite3を利用していた。)

  • バージョン指定無しのrailsコマンドでプロジェクトを作る。プロジェクト名test_slip202。
$ rails test_slip202
  • app、db、po、locale、public/stylesheetsフォルダを同じフォルダ階層にまるごとコピーした。
  • app/controllers/application.rbをRails2.0.2環境の初期設定の状態に変更した。
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time

  # See ActionController::RequestForgeryProtection for details
  # Uncomment the :secret if you're not using the cookie session store
  protect_from_forgery # :secret => '1e472fc313f2cb0b34cba5f35feb8895'
  
  init_gettext 'test_slip'
end
  • config/environment.rbの最後に以下を追記した。
# config/environment.rb
...(中略)...
require 'gettext/rails'

# fieldWithErrorsのタグを<span>に変更する。
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  "<span class=\"fieldWithErrors\">#{html_tag}</span>"
end
  • paginateメソッドが定義されていないとエラーが出るので...
NoMethodError in SlipsController#index
undefined method `paginate' for #
  • とりあえず、プラグインclassic_paginationをインストールしてしのぐ。
$ cd test_slip202
$ script/plugin install classic_pagination
  • 明細行の削除が出来ないことに気付く。Firebugのconsoleウィンドウで確認すると、以下のように表示されている。startcolor:のクォーテーションが次第に増えている...。
  • app/controllers/slips_controller.rbのdelete_rowメソッド中のvisual_effect呼び出しの「:startcolor=>"'#666666'"」オプションを取り除くと、正常に削除できるようになった。
try {
$$("#j946404879 th").each(function(value, index) {
new Effect.Highlight(value,{duration:2, startcolor:''#666666''});
});
$$("#j946404879 td").each(function(value, index) {
new Effect.Highlight(value,{duration:2, startcolor:'''#666666'''});
});
$$("#j946404879 input").each(function(value, index) {
new Effect.Highlight(value,{duration:2, startcolor:''''#666666''''});
});
...(中略)...

以上の修正をしたら、Rails2.0.2環境でも問題なく動くことが分かった。(ただし、全くRails2.0.2らしい機能を活かしていない...。とりあえず古いスタイルのコーディングであっても動く、ということが理解出来た。)

なぜvisual_effectの:startcolorオプションでエラーになるのか?

  • Rails2.0.2の上記エラーでハマった。検索してもどうにも分からず、その部分のソースコードを見てみた。以前と比較して、2.0.2ではオレンジ色の部分が変更されていた。(その他にも:endcolor, :direction, :scaleMode, :restorecolorで同じような状況になる可能性がある)
  • おそらく、この変更は:endcolor=>"'#666666'"(クォーテーションで囲った文字列)を:endcolor=>"#666666"(自然な文字列)で指定出来るようにしたかったのではないだろうか...。
      def visual_effect(name, element_id = false, js_options = {})
        element = element_id ? element_id.to_json : "element"
        
        js_options[:queue] = if js_options[:queue].is_a?(Hash)
          '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
        elsif js_options[:queue]
          "'#{js_options[:queue]}'"
        end if js_options[:queue]
        
        [:endcolor, :direction, :startcolor, :scaleMode, :restorecolor].each do |option|
          js_options[option] = "'#{js_options[option]}'" if js_options[option]
        end

        if TOGGLE_EFFECTS.include? name.to_sym
          "Effect.toggle(#{element},'#{name.to_s.gsub(/^toggle_/,'')}',#{options_for_javascript(js_options)});"
        else
          "new Effect.#{name.to_s.camelize}(#{element},#{options_for_javascript(js_options)});"
        end
      end
  • 自分がvisual_effectを呼び出しているコードは以下で...以下のようにやってしまうとvisual_effectを呼び出すごとに、クォーテーションが増え続けるという状況になっている。
module SlipsHelper
  # 1行すべてをハイライト処理する
  def highlight_row(page, id, js_options={})
    tags = %w{th td input textarea select}
    tags.each do |tag|
      page.select("##{id} #{tag}").each {|element| page.visual_effect(:highlight, element, js_options)}
    end
  end
...(中略)...
  • 悩んだ結果、app/application_helper.rbにvisual_effectメソッドをapplication_helper.rbにコピーして、以下のように追記してみた。(オレンジ色の部分。クォーテーションで既に囲まれていたら何もしない条件に変更した。)
# ヘルパー: app/helpers/application_helper.rb
...(中略)...
module ActionView
  module Helpers
    module ScriptaculousHelper
      def visual_effect(name, element_id = false, js_options = {})
        element = element_id ? element_id.to_json : "element"
        
        js_options[:queue] = if js_options[:queue].is_a?(Hash)
          '{' + js_options[:queue].map {|k, v| k == :limit ? "#{k}:#{v}" : "#{k}:'#{v}'" }.join(',') + '}'
        elsif js_options[:queue]
          "'#{js_options[:queue]}'"
        end if js_options[:queue]
        
        [:endcolor, :direction, :startcolor, :scaleMode, :restorecolor].each do |option|
          js_options[option] = "'#{js_options[option]}'" if js_options[option] && !(/\A(['"]).+\1\z/ =~ js_options[option])
        end
...(中略)...


以上で、:startcolorオプションも指定出来るようになり、Rails2.0.2で問題なく稼働出来るようになった!

*1:Mac OS X 10.5 Leopardには最初からRubyRailsもgemインストール済み。だから自分のMacBook環境では余計な手間無しで簡単にアップデートが可能だった。