route.rbファイルを見てください。schedules小アプリケーションを作成して動作させた時点で、route.rbには(1)の記述が自動でなされています。
(1)もとから書いてある記述
map.resources :schedules
(2)ワレワレ独自の記述
map.connect '/schedules/agenda', :controller=>'schedules', :action=>'agenda'
gem update --system
nothing to update
これは、gemをアップデートするソフトウェアそのものが変わってしまったからです。まず、「rubygems-update」というソフトウェアをオンラインでインストールしなければならなくなりました。
gem install rubygems-update
1 gem installed
update_rubygems
ゆえに、本書 172ページにおきまして、実行例8を行うと
そこで、この「places小アプリケーション」を一度削除します。
ruby script/destroy scaffold place
変更点をお知らせくださいました読者の皆様、どうもありがとうございました。
申し訳ありません。これ、間違いです。
「Rubyリファレンスマニュアル」によりますと、Rubyには厳密な意味での関数はないそうです。
ただ、メソッドの中で、「関数形式で呼び出せる」「関数のように使える」ものがあるそうで、上記マニュアルでも「組み込み関数」という用語が使われているくらいですから、あながち、ウソッパチでもないのですが...
そこで、本書で「関数」と書いてある箇所は「関数のように使えるメソッド」のことだとお考えください。
プログラムの動作には、全く問題ありません。
gem install sqlite3-ruby .... ERROR: Error installing sqlite3-ruby: ERROR: Failed to build gem native extension. ....
2008年10月下旬の時点では、gemでインストールできるsqlite3-rubyのWindows版は1.2.3です。そこで、以下のようにバージョンを直接指定します。
gem install sqlite3-ruby --version 1.2.3
しかし、本書のいくつかのページでは、表のデータをさらに加工して表示するようにしました。
ただしできたのは「HTML文書」のみ。これと同じような形式で「XML文書」を出せるか、という問題(p224)に対して、本書では取り扱う時間がありませんでしたね。
ここでやってみましょう。ただし、サポートページが書籍より長くなってしまってはアレですから、説明は多少はしょります。
まずは簡単な例から行きましょう。本書のサンプル「members.html.erb」の完成形です(p286)。 Rails2には「その場でxmlを吐け」というメソッド「to_xml」があります。これは「find」や「validates_ナントカ」メソッドと同じように、「activerecord」の「RDoc」に載っています。これを使います。
(1)to_xmlメソッドを試してみる
「members_controller.rb」の「def index」ブロックを編集します。
respond_to do |format| format.html # index.html.erb format.xml { render :xml => @members } end
太字のところを変えます。
format.xml { render :xml => @members.to_xml }
これで、以下のURLにアクセスしてみてください。
同じように、XML文書が表示されましたね。つまりリスト2の使い方でいいんだなということが確かめられたのです。
(2)要らないものは表示しない
ではこのto_xmlメソッドに条件をつけてみましょう。「acc」列の値からメールアドレスを作成して出すのですから、もとの「acc」列の値は要りませんね。
リスト2を以下のようにしてみましょう。
format.xml { render :xml => @members.to_xml(:except=>[:acc]) }
これで「acc」タグの中身が表示されなくなりました。
(3)データの加工は「モデル」に書く
「acc」列の値からメールアドレスを作成する、という作業は、「Memberモデル」の定義に「メソッド」として書きます。「member.rb」に以下のメソッドを書き加えましょう。
def mailadd return self.acc+"(naruto)hajimete.rubirel.com" end
インターネットでは悪徳ロボットにメールアドレスデータをさらわれスパムの餌になると困りますので「@」マークを(naruto)という文字に置き換えてあります。最近はもしかすると「@」の代わりに「at」などと書いても狙われるかもしれないからです。さて、
これ、「self.mailadd」じゃないの?
と、本書を読んだ人は思ったかもしれません。
すみません。筆者もわかりません。メソッドの定義のときに「self」をつけないとエラーになる場合と、つけるとかえってエラーになる場合があります。二択ですから筆者はエラーにならない方法を採用しています。誰かRubyに詳しい人に、聞いてみてください。
このように定義しておいてから、「members_controller.rb」に戻ってリスト3をさらに編集します。
format.xml { render :xml => @members.to_xml(:except=>[:acc], :methods=>[:mailadd]) }
本日の予定の表示も同様です。「member.rb」にリスト6のようなメソッド「placetoday」を作ります。
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のように、メソッドを付け足します。
format.xml { render :xml => @members.to_xml(:except=>[:acc], :methods=>[:mailadd, :placetoday]) }
これは、別途「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」ブロックで制御するのが最もアタマを悩まさずに済む方法です。
ただいろいろと周辺手続きがめんどくさいので、本書では書かなかったのです。ちょっと白状しますと、その時点ではアンマリヨクワカンナカッタというのもあります。つまりそれだけ、作業がめんどくさいということです。
ですからこの項を完結させるためにはまず次の項をやっておく必要があります。いや、これもいい勉強です。
このagenda2_controller.rbにはリスト8のように書いておきます。
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」ファイルです。エディタで開いたら最初のほうを見てください。
map.resources :schedules map.resources :places map.resources :members
ココにリスト10を付け足します。これは特に、「agenda2(.htmlを省略)」と「agenda2.xml」とを使い分けたい場合に必要なのです。
map.resources :agenda2
そういう名前にするのがこの「Builderプロジェクト」の決まりです。作ったら、まずはリスト11のように書いてみましょう。
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でも「ページのソース」ではちゃんと出ていますからそれで我慢するという方法もあります。
枠組みはオッケー、というところです。
(6)Scheduleデータのtheday値を表示させる 次に表示させるのは、表「schedules」の「theday」列のデータです。リスト12のように書きます。
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
(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のように書きます。
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のように書きます。
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」が並びます。
なかなかの作業かつ微妙な設定ではありましたが、こんなもんで独自のXML文書が作成できるというのは、実はタイヘンな便利さだと思います。