「はじめてのRuby on Rails2」著者サポートページ

工学社刊「はじめてのRuby on Rails2」の著者によるサポートページです。本書で書ききれなかったこと、それからなるべくないほうがよいのですが本書にもし間違いがあった場合その訂正等を書いていきます。参考にしていただければ幸いです。 清水 美樹

Windows用Ruby最新事情

前著「はじめてのRuby on Rails」サポートページ


agendaページのURL設定について(本書208-209ページ)

Ruby on Rails2では、どのページをなんというURLで表示させるかを,routes.rbというファイルに記述します。本書のアプリケーションですとgroupware2フォルダのconfigフォルダの中です。
本書では「schedules」というデータベース表を別の観点から表示する「agenda」というページを独自に作成します。
この「agenda」ページ、やっぱりschedulesを使うので、「http://localhost:3030/schedules/agenda」としたいところですが、本書作成時に筆者にはどうにもそれが実現できなかったので、別のURLにしておきました(209ページのコラム)
今回読者の方に教えていただきました。どうもありがとうございます。

route.rbファイルを見てください。schedules小アプリケーションを作成して動作させた時点で、route.rbには(1)の記述が自動でなされています。

(1)もとから書いてある記述

 map.resources :schedules
この「前に」(2)のように書きます。

(2)ワレワレ独自の記述

  map.connect '/schedules/agenda', :controller=>'schedules', :action=>'agenda'
これで、「同じ小アプリケーション」の中に好きな名前のページ(アクション)を追加することができます。

railsとgemのアップデート

Ruby on Railsの最近のバージョン(2.2)を扱うには、gemの1.3以上が必要になりました。ところが、gemの1.2などのバージョンから以下のコマンドでオンラインアップデートを試みると、失敗します。
gem update --system
とやりますと、
nothing to update
と出て終わってしまいます。

これは、gemをアップデートするソフトウェアそのものが変わってしまったからです。まず、「rubygems-update」というソフトウェアをオンラインでインストールしなければならなくなりました。

gem install rubygems-update
これは無愛想に
1 gem installed
のようなメッセージで完了しますので、そのあと
update_rubygems
を行うと、gemのアップデートが行われます。

上書きができなくなった「script/generate」

Ruby on Railsの最近のバージョン(2.2)では、「ruby script/generate...」コマンドによる「小アプリケーション」の作成において、もとからあるアプリケーションに上書きする形で作成ができなくなりました。

ゆえに、本書 172ページにおきまして、実行例8を行うと

The name 'PlacesHelper' is either already used in your application or reserved by Ruby on Rails.
Please choose an alternative and run this generator again.
というエラーが出ます。

そこで、この「places小アプリケーション」を一度削除します。

ruby script/destroy scaffold place
その後あらためて、実行例8を行っていただきます。

変更点をお知らせくださいました読者の皆様、どうもありがとうございました。


(すみません)Rubyにおける関数とメソッド

本書の随所(たとえば218ページ)で、Rubyには「関数」と「メソッド」があるというような記述をしておりました。

申し訳ありません。これ、間違いです。

Rubyリファレンスマニュアル」によりますと、Rubyには厳密な意味での関数はないそうです。
ただ、メソッドの中で、「関数形式で呼び出せる」「関数のように使える」ものがあるそうで、上記マニュアルでも「組み込み関数」という用語が使われているくらいですから、あながち、ウソッパチでもないのですが...

そこで、本書で「関数」と書いてある箇所は「関数のように使えるメソッド」のことだとお考えください。
プログラムの動作には、全く問題ありません。


sqlite3-rubyがgemでインストールできないとき

gemコマンドでsqlite3-rubyをインストールしようとして、以下のメッセージとともに失敗することがあります。

gem install sqlite3-ruby

....
ERROR:  Error installing sqlite3-ruby:
       ERROR: Failed to build gem native extension. 
....
このエラーの原因は、gemコマンドが常に最新版のパッケージを探してくるのに対して、Windows版のみ最新版がないことによると考えられます。

2008年10月下旬の時点では、gemでインストールできるsqlite3-rubyのWindows版は1.2.3です。そこで、以下のようにバージョンを直接指定します。

gem install sqlite3-ruby --version 1.2.3
とりあえずの応急措置です。gemで利用できるアプリケーションの探し方や、gem以外の方法でインストールする方法などは、申し訳ありませんが日を改めて...
出てくれるといいですね。Windows版。

独自のXML文書を書き出す方法(1)

*本書を最後まで学習した方向けに書いてあります。
Ruby on Rails2(以下Rails2)では、URLを「members.xml」のように拡張子をつけて指定すれば、表「members」の全データがXML形式で書き出されるようになっています。(本書p129)

しかし、本書のいくつかのページでは、表のデータをさらに加工して表示するようにしました。

ただしできたのは「HTML文書」のみ。これと同じような形式で「XML文書」を出せるか、という問題(p224)に対して、本書では取り扱う時間がありませんでしたね。

ここでやってみましょう。ただし、サポートページが書籍より長くなってしまってはアレですから、説明は多少はしょります。

まずは簡単な例から行きましょう。本書のサンプル「members.html.erb」の完成形です(p286)。 Rails2には「その場でxmlを吐け」というメソッド「to_xml」があります。これは「find」や「validates_ナントカ」メソッドと同じように、「activerecord」の「RDoc」に載っています。これを使います。

(1)to_xmlメソッドを試してみる

members_controller.rb」の「def index」ブロックを編集します。

リスト1 HTMLとXMLを使い分けるところ
respond_to do |format|
  format.html # index.html.erb
  format.xml  { render :xml => @members }
end

太字のところを変えます。

リスト2 to_xmlメソッドは使えるか
  format.xml  { render :xml => @members.to_xml }

これで、以下のURLにアクセスしてみてください。

http://localhost:3000/members.xml

同じように、XML文書が表示されましたね。つまりリスト2の使い方でいいんだなということが確かめられたのです。

(2)要らないものは表示しない

ではこのto_xmlメソッドに条件をつけてみましょう。「acc」列の値からメールアドレスを作成して出すのですから、もとの「acc」列の値は要りませんね。
リスト2を以下のようにしてみましょう。

リスト3 「acc」タグは表示しない
format.xml  { render :xml => @members.to_xml(:except=>[:acc]) }

これで「acc」タグの中身が表示されなくなりました。

(3)データの加工は「モデル」に書く

「acc」列の値からメールアドレスを作成する、という作業は、「Memberモデル」の定義に「メソッド」として書きます。「member.rb」に以下のメソッドを書き加えましょう。

リスト4 「member.rb」に 「mailadd」メソッドを加える
def mailadd
  return self.acc+"(naruto)hajimete.rubirel.com"
end

インターネットでは悪徳ロボットにメールアドレスデータをさらわれスパムの餌になると困りますので「@」マークを(naruto)という文字に置き換えてあります。最近はもしかすると「@」の代わりに「at」などと書いても狙われるかもしれないからです。さて、

これ、「self.mailadd」じゃないの?

と、本書を読んだ人は思ったかもしれません。

すみません。筆者もわかりません。メソッドの定義のときに「self」をつけないとエラーになる場合と、つけるとかえってエラーになる場合があります。二択ですから筆者はエラーにならない方法を採用しています。誰かRubyに詳しい人に、聞いてみてください。

このように定義しておいてから、「members_controller.rb」に戻ってリスト3をさらに編集します。

リスト5 「mailadd」メソッドの結果も表示する
  format.xml  { render :xml => @members.to_xml(:except=>[:acc], 
                    :methods=>[:mailadd]) }

図1 「mailadd」タグが表示された

本日の予定の表示も同様です。「member.rb」にリスト6のようなメソッド「placetoday」を作ります。

リスト6 「member.rb」に 「placedotoday」メソッドを加える
def placetoday    
  found=Schedule.find(:first, 
      :conditions=>["member_id=? and theday=?", 
        self.id, Date.today]
    )
      
  if(found)
    return found.place.name
  else
    return "なし"
  end 
end

「なし」という日本語を直接ファイルに書き込んだので、ファイルは「UTF-8(N)」で保存する必要があります。めんどくさかったら「none」とか適当な英語で構いません。

一方、「members_controller.rb」のほうはリスト7のように、メソッドを付け足します。

リスト7 「mailadd」メソッドの結果も表示する
format.xml  { render :xml => @members.to_xml(:except=>[:acc], 
    :methods=>[:mailadd, :placetoday]) }

図2 結構複雑な処理結果も表示できた

独自のXML文書を書き出す方法(2)

*本書を最後まで学習した方向けに書いてあります。
さて問題はアタマの先から足の先まで勝手に作り上げた「agenda」ページです。

これは、別途「XML文書を書き出すファイル」を作ってしまうほうがよいでしょう。

HTML文書を書き出すファイルとして「ナントカ.html.erb」を作ったように、「ナントカ.xml.builder」というファイルを作ってやればいいのです。

この「builder」という拡張子は、RailsでXML文書を吐かせるための拡張機能プロジェクト「Builder」の成果物で、Rails2に標準でサポートされています。(プロジェクトページ:http://builder.rubyforge.org/

ただし、本書のままではひとつ困った点があります。

本書では小アプリケーション「schedules」の中に無理矢理「agenda.html.erb」を作りましたが、Railsでは表示するページのURLは「コントローラ名(members, schedulesなど)」をかなり強力によりどころにしています。

ひらたく言えば、このまま「agenda.xml」とURLを指定しても、「そんなルートはありません」と言われてしまうのです。

ですから、ここは素直に「view」フォルダの下に「agenda」というフォルダを作って、そこに「index.html.erb」と「index.xml.builder」というファイルを置き、これらを「agenda_controller.rb」の「def index」ブロックで制御するのが最もアタマを悩まさずに済む方法です。
ただいろいろと周辺手続きがめんどくさいので、本書では書かなかったのです。ちょっと白状しますと、その時点ではアンマリヨクワカンナカッタというのもあります。つまりそれだけ、作業がめんどくさいということです。

ですからこの項を完結させるためにはまず次の項をやっておく必要があります。いや、これもいい勉強です。


独自の「コントローラ」を作って使う

*本書を最後まで学習した方向けに書いてあります。
(1)「agenda2_controller.rb」を作成 どこから作っていけばいいか迷うほどあちこちやらないといけないのですが、とりあえず「controllers」フォルダに「agenda2_controller.rb」を作りましょう。前の「agenda」ページは勿体ないので、別途作り直すわけです。
ヘンな名前ですが問題ありません。専用の表を直接扱うわけではないので、単数・複数の命名規則には従わなくてもいいのです。

このagenda2_controller.rbにはリスト8のように書いておきます。

リスト8 agenda2_controller.rb
class Agenda2Controller < ApplicationController

  def index
    
    @schedules = Schedule.find(:all, :group=>'theday', :order=>'theday')
    @members= Member.find(:all)
    
  respond_to do |format|
    format.html
    format.xml{render:layout=>false}
  end
 end
end

これは「schedules_controller.rb」に書いた「def agenda」ブロックとかなり同じです。ただ、「schedules_controller.rb」ファイルにはクラス「SchedulesController」の定義が書かれているのに習って、こちらも「Agenda2Controller」というクラスの定義にします。

また「ページとその動作の名前」も、安心して使える「index」に変えました。
大事なのは「format.xml」の{...}の中の説明書きが変わっていることです。「独自のXMLを使うヨ」という断りだと考えておいてください。

(2)「views/agenda2/index.html.erb」を作成

「views」フォルダの下に「agenda2」フォルダを作り、そこに「index.html.erb」を作成します。中身は本書で作った「agenda.html.erb」と全く同じで構いません。つまり、コピーしてファイル名だけ変えりゃいいんです。

(3)「views/layouts/agenda2.html.erb」を作成

忘れやすいのがコレです。作っておかないと、データは正常に表示されてもレイアウトはヘロヘロです。
作るのは簡単です。すでに作ってある、たとえば「schedules.html.erb」をその場にコピーして、ファイル名を「agenda2.html.erb」に変えます。そして、中の「<title>」タグの中身を適当に変えます。めんどくさかったら、もともとの「schedules」ページと自分で混乱しないようにすれば、変えなくても特に問題はありません。

(4)「routes.rb」を編集

URL命名規則を決める「routes.rb」ファイルです。エディタで開いたら最初のほうを見てください。

リスト9 routes.rbのはじめのほうに書いてある
  map.resources :schedules
  map.resources :places
  map.resources :members

ココにリスト10を付け足します。これは特に、「agenda2(.htmlを省略)」と「agenda2.xml」とを使い分けたい場合に必要なのです。

リスト10 agenda2というルートを知らせる
  map.resources :agenda2
ここまでやったら、以下のURLにアクセスしてみましょう。

http://localhost:3000/agenda2
「agenda」ページと同じ中身が表示されるはずです。もし問題がある場合は、プログラムの修正のほかにも、ファイルやフォルダの名前、ファイルの位置などが間違っていないか確認しましょう。
つづき:独自のXML文書を書き出す方法(2)
さて、これで独自のXML文書をファイルから読み込んで書き出す準備が整いました。では作業を続けましょう。 (5)「views/agenda2/index.xml.builder」を作成する

そういう名前にするのがこの「Builderプロジェクト」の決まりです。作ったら、まずはリスト11のように書いてみましょう。

リスト11 views/agenda2/index.xml.builder(その1)
 xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
xml.agenda do
end

ここで注意です。index.xml.builderを保存するとき、文字コードは「UTF-8N」が選べる場合、それで保存します。日本語を使ってなくても、です。

また、Windows環境では、改行はCR+LFがデフォルトですが、これを変えないようにします。筆者の実験では、こうした文字コードや改行の細かい設定の違いで、特にInternet Explorerの場合、エラーになったり正常に表示されなかったりします。

「xmlなんて語は知りません(unknown)」というエラーが出ても信用してはいけません。これはRailsでサポートされているプロジェクトですから、Railsの命名規則に従い、「.xml.builder」という拡張子をつけて、「xml」という語を使えばRailsはちゃんとわかってくれるはずなのです。それでわかってもらえないといのは、文字コードや改行記号の違いにより、プログラムに影響を与えるようなコードが発生したためと考えられます。 さらに、設定をいろいろ変えても同じエラーや結果が繰り返し表示される場合、ファイルをゼロから作り直したり、Rubyのサーバ(WEBrick)を再起動する必要があるかも知れません。

簡単なコードで便利に出力してくれる反面、微妙な設定の違いで結果が異なるようです。

図3のような結果が出たらラッキーです。どうしても出ない場合は、Firefoxで見るか、IEでも「ページのソース」ではちゃんと出ていますからそれで我慢するという方法もあります。

図3 文字コードと改行記号に気をつけて、これが出たらラッキー

枠組みはオッケー、というところです。

(6)Scheduleデータのtheday値を表示させる 次に表示させるのは、表「schedules」の「theday」列のデータです。リスト12のように書きます。

リスト12 views/agenda2/index.xml.builder(その2)
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
xml.agenda do
  for schedule in @schedules
      xml.schedule do
        xml.theday(schedule.theday)
      end
  end
end

図4 「theday」タグが表示された。日付の中身がちょっとヘンなのはデータ入力の都合なので気にしないでください

図5「agenda」の終了タグができた

(6)「agenda2_helper.rb」を作る

本書で「agenda.html.erb」を書いたときは、HTML文書で書きやすいような値を出力する関数「findShed」を、「schedules_helper.rb」に書きました。でも、これはXML文書には適しません。ですから、XML向けの関数「findSched2(実は、本書p222の「改良前findSched」と同じ)」を作るのですが、どうせですから「agenda2_helper.rb」も新しく作ってしまいましょう。

「app/helpers」フォルダに「agenda2_helper.rb」を作成したら、リスト12のように書きます。

リスト12 agenda2_helper.rb
module Agenda2Helper

  def findSched2(member_id, theday)
    found=Schedule.find(:first, 
        :conditions=>["member_id=? and theday=?", 
            member_id, theday]
    )
      
    if(found)
      return found.place.name
    else
      return 'なし' 
    end     
  end
end

これも「なし」という日本語を使ってしまったので「UTF-8(N)」で保存です。めんどくさければ英語で構いません。

(7)関数findSched2で処理した結果をXMLに書き出す リスト13のように書きます。

リスト13 views/agenda2/index.xml.builder(完成)
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
xml.agenda do
  for schedule in @schedules
    xml.theday(schedule.theday)
    for member in @members
        xml.member do
          xml.name(member.name)
          xml.place(findSched2(member.id, schedule.theday))
        end
      end
    end
  end
end

「xml.agenda do」「for schedule」「xml.schedule do」「for member」「xml.member do」のそれぞれに対して、合計5つの「end」が並びます。

図6 夢にまで見た「予定表」のXML表示

なかなかの作業かつ微妙な設定ではありましたが、こんなもんで独自のXML文書が作成できるというのは、実はタイヘンな便利さだと思います。