テキストフィールドが複数あるとEnter送信されない

メモ
テキストフィールドを1つのみ含むフォームはEnter送信される。

<form>
  <input type="text" />
</form>

テキストフィールドを複数含むフォームはEnter送信されない。

<form>
  <input type="text" />
  <input type="text" />
</form>

HTML学んで結構長いがこんなん知らなかった。
ちなみに以下はテキストフィールドが1つなのでEnter送信される。

<form>
  <input type="text" />
  <input type="hidden" />
</form>

ActionMailer::Baseをインスタンス化できない

メモ
ActionMailerの単体テストを書こうと思い、最初はActionMailer.deliver_???のテストを書いたが次の点が嫌だなと思った。
・deliver_???は自分で書いたコードではない(???が自分で書いたコードだ)
・???で設定したビューで使用することを設定したインスタンス変数の中身をテストするのにdeliver_???が返すオブジェクトのbodyメソッドを調べなければいけない。つまりActionMailerの単体テストを書きたいのにビューに依存したテストを書くことになる。
・テストがやや冗長になる。

以上のことからもっとシンプルに単体テストを書くためにActionMailer::Baseの継承クラスをインスタンス化して直接自分が書いた???メソッドを呼び出そうと考え、以下のようなコードを書いた。

class InquiryMailer < ActionMailer::Base
  def reply(user)
    @body[:message] = 'テスト'
  end
end

describe InquiryMailer, "#replyを実行した場合" do
  befor(:each) do
    @inquiry_mailer = InquiryMailer.new
    @inquiry_mailer.reply(User.new)
  end

  it "@body[:message]はテストであること" do
    body = @inquiry_mailer.instance_variable_get(:@body)
    body[:message].should == 'テスト'
  end
end

しかし残念ながらInquiryMailer.newの時点で期待通り動かない。つまりインスタンス化できず、@inquiry_mailerにはnilが代入される。
ActionMailer::Baseのinitializeメソッドのソースを見てみると次の通り第一引数を渡さないとダメみたい。

  def initialize(method_name=nil, *parameters) #:nodoc:
    create!(method_name, *parameters) if method_name
  end

それで引数を渡した。

  @inquiry_mailer = InquiryMailer.new(:reqly, User.new)

それでもNoMethodError: undefined method `mailer' for #などという例外が発生し意図するように動かなかった。

これ以上ActionMailerの詳細に突っ込むのが嫌になったので最初のdeliver_???をテストすることにした。

Rspec 他のメソッド呼ぶスペックの書き方

メモ

class A
  def call_other_method
   other_method1
  end
  
  def other_method1
  end
  
  def other_method2
  end
end

describe A, "#call_other_methodを実行した場合" do
  before(:each) do
    @a = A.new
  end
  
  it "other_method1を呼ぶこと" do
    @a.should_receive(:other_method1).with(no_args)
    @a.call_other_method
  end
  
  it "other_method2を呼ぶこと" do
    @a.should_receive(:other_method2).with(no_args)
    @a.call_other_method
  end
end

A#call_other_methodはA#other_method2を呼ぶため、2番目のitは失敗する。

他クラスのメソッドを呼ぶ場合

class A
  def call_other_class_method
    B.klass_method
  end
end

class B
  def self.klass_method
  end
end
describe A, "#call_other_class_methodを実行した場合" do
  it "B::klass_methodを呼ぶこと" do
    B.should_receive(:klass_method).with(no_args)
    a = A.new
    a.call_other_class_method
  end
end

呼ぶことだけを確認できるって素晴らしい。
何故なら呼ばれたメソッドの責務を呼ぶ側が負わなくていい。
つまりはDRYなスペックが書けるということだ。

render_to_stringメソッドとBuilderを使ってXML文字列を生成する方法

メモ
Builderを使ってXMLのレスポンスを生成するには以下のようにrespond_to()を使うのだが・・・

# ビュー(show.xml.builder)
xml.diary do
  xml.title @diary.title
end
# Diariesコントローラ
def show
  @diary = Diary.find(params[:id])
  respond_to do |format|
    format.xml
  end
end

レスポンスではなく文字列としてXMLを取得したい時は次のようにするとできる。

# Diariesコントローラ
def show
  @diary = Diary.find(params[:id])
  xml = render_to_string(:template => 'diaries/show.xml.builder',  :layout => false)
  # 何かの処理が続く
end

ActiveRecordが生成するSQLをRailsのコンソールで確認する方法

メモ
ActiveRecordが生成するSQLは通常、/log/development.logなどのログファイルに吐かれるが、これをRailsのコンソールに出力する方法。
実はとても簡単でログの吐き出し先を標準出力に指定するだけ。

ruby script/console

# ログの出力先を指定する。以上。
ActiveRecord::Base.logger = Logger.new(STDOUT)

# ActiveRecordを操作すると以下のようにSQLのログが出力される。
User.find(:first)
[4;36;1mSQL (0.0ms)[0m   [0;1mSET NAMES 'utf8'[0m
[4;35;1mSQL (0.0ms)[0m   [0mSET SQL_AUTO_IS_NULL=0[0m
[4;36;1mUser Load (0.0ms)[0m   [0;1mSELECT * FROM `users` LIMIT 1[0m
[4;35;1mUser Columns (16.0ms)[0m   [0mSHOW FIELDS FROM `users`[0m

以下を参考にしました。感謝。
http://weblog.jamisbuck.org/2007/1/8/watching-activerecord-do-it-s-thing

バージョンを指定してRailsスケルトンを作成する方法

メモ
複数バージョンのRailsをインストールしている場合にRailsケルトンを作成すると、インストールされている中の最新のバージョンのRailsケルトンが作成されるが、他のバージョンのRailsケルトンを作成するには次のようにする。

# rails _version_ app_name
rails _2.1.0_ old_skeleton

以下を参考にしました。感謝。
http://d.hatena.ne.jp/moro/20080114/1200283950