Rails Mimeタイプを登録する方法
メモ
/config/environment.rbなどに以下を記述
Mime::Type.register "text/plain", :sql
するとコントローラで以下のように書ける。
def index @diaries = Diary.find(:all) respond_to do |format| format.html # index.html.erb format.xml { render :xml => @diaries } format.sql { } #何かの処理 end end
テキストフィールドが複数あると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