続き
続きをやります。
前回内容とKPTを見て思い出します。
多対多の解説を見て、失敗した事に気づきました。
それは、サンプルがログインシステム(第二章)の画面を使用している・・・
えぇ〜〜〜!!しまった。
ということで、ソースコードとDBデータのマージをしました。
Viewで多対多のデータを利用する
welcomeページに多対多レコードからSNS情報表示するように記述しました。
<h1>Account#welcome</h1> <p>Find me in app/views/account/welcome.rhtml</p> welcome, <%= h @me.name %>! <h2>communities ( <%= @me.communities.size %> )</h2> <% @me.communities.each {|community| -%> <%= link_to h(community.name), :controller => "communities", :action => "show", :id => community %><br> <% } -%> <h2>Diary</h2> <% @me.topics.each {|topic| -%> <h3><%= topic.written_on %> <%= h topic.title %></h3> <%= textilize topic.content %> <% } -%>
確認
解説を見ながらソースコードを順を追ってみる。
- 前提
- 第二章のソースが完成されている。
- @meにはログインされたユーザー情報が格納されている
【1】データの取得
meにはUser情報が格納されているので、ActiveRecordのMODEL関連付け設定により@meに関連付けされた、コミュニティや
日記情報を「@me.communities」「@me.topics」という感じで、アクセスできる。
【2】データの表示
<% -%>はロジックコード、<%= %>は表示。JSPやPHPと使い方は同じ感じ。
【3】ヘルパーメソッドを使う
あとは、取得した配列をヘルパーメソッドを使って、リンク張ったり、表示形式などを整える。
よし!完成。
メソッドフック
メソッドの実行前後に、コールバックという機能でフックさせることができるらしい。
インターセプターと同じ感じなんでしょうか??
例えばこんな事ができるとのこと。
- セッションのログイン状態確認
- バリデーションの前に値を加工
- 保存前に依存関係を解決
コールバックの呼ばれる順番もあるので、これは用途によって覚えておきたい。
こんな感じでModelにメソッド定義すれば使えるらしい。
class User < ActiveRecord::Base # 〜略〜 def self.authenticate(name, password) find_first([ "name = ? and password = ?", name, password ]) end end
モデル中心に色々コードを書くのですね。なるほど。
最後トランザクション
saveの時は暗黙的にDBのトランザクションを使用しているらしく、明示的にUser.transactionメソッドを使ってもできるらしい。
終った!!第四章はすごかった。
Rails初心者には一つの壁っぽい。もうちょっとActiveRecordを使ってみたい。
第4章後半分の振り返り(KPT法使うよ)
ぷちKPT
- KEEP【良かった事、続けていきたい事】
- PROBLEM【悪かったこと、改善したい事】
- Viewに関しては理解が足りない。
- インターセプターとコールバックの違いがよくわからない。
- vimの設定ファイルを触っていた時間が多かった。
- TRY【今後取り込みたいこと】
- Viewをたくさん書く。
- ActiveRecordの機能を色々使ってみる。(抽象的な事なので優先度低で取り組む)
- Scaffoldだけじゃなく、初心者かHOWTOから一歩進んだModelについて学ぶ。
- 他のヘルパーメソッドを試す。
Railsのテストに関して
TestのクラスはRuby1.8標準のTest::Unitクラスを使うらしい。
setup、teardownメソッドで初期化と後始末ができて、テストメソッドの先頭はtestで始めるという規約があるとのこと。
テストメソッドはassertが用意されていているらしい。
- assert
- assert_nil
- assert_equal
- assert_raise
他にも色々あるみたいです。
テスト専用のDBも使用できるとのことで、fixtureという機構を用いてデータベースを構築するらしい。
rakeでまとめてテスト実行もできる。
fixtureに関して
fixtureはモデルテストの初期値を設定するしくみで、ActiveRecordを通してDBのテーブルを元に作られるらしい。
DBのテストはアプリケーションでDB値を書き換えしてしまうので、assertが書きにくい為、予め初期値をYAML形式で
保持しておくことができらしい。
さっそくテストをやってみる。
test/unit/user_test.rbにテストケースを書いて、Fixturesにデータを定義する
bob: id: 3 name: bob password: s3cret
require File.dirname(__FILE__) + '/../test_helper' class UserTest < Test::Unit::TestCase fixtures :users # 存在するデータに対するテスト def test_bob assert_equal "bob", @bob.name assert_equal "s3cret", @bob.password end # 認証で存在するデータと存在しないデータをテストする def test_auth assert User.authenticate("bob","s3cret") assert_nil User.authenticate("bob","hogehoge") end end
そして、unitテスト実行
C:\InstantRails\rails_apps\wdpress\test\unit>ruby user_test.rb
1) Error: test_bob(UserTest): NoMethodError: You have a nil object when you didn't expect it! The error occurred while evaluating nil.name user_test.rb:8:in `test_bob' 2 tests, 2 assertions, 0 failures, 1 errors
失敗は発生しないはずが、インスタンスメソッドに対してテストを行うメソッド、test_bobでエラーが発生している。
pメソッドで、ログ出力したらインスタンスがnilだった。
データに対する仕組みがよくわかっていないので、とりあえず先に進むことにする。
コントローラーのテスト
functionalディレクトリにcontroller用のテストファイルがあるらしい。
ログイン機能に対するテストを書いた
require File.dirname(__FILE__) + '/../test_helper' require 'account_controller' # Re-raise errors caught by the controller. class AccountController; def rescue_action(e) raise e end; end class AccountControllerTest < Test::Unit::TestCase fixtures :users # 自動生成されたコード def setup @controller = AccountController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end # 認証をPOST値からチェック def test_auth_bob post "authenticate", "me" => {"name" => "bob", "password" => "s3cret"} assert_redirected_to :action=>"welcome" assert_equal @bob, session["me"] end # 不正なログインのチェック def test_invalid_login post "authenticate", "me" => {"name" => "bob", "password" => "hogehoge"} assert_redirected_to :action => "login" assert_nil session["me"] end # ログインとログアウトをチェック def test_login_logout post "authenticate", "me" => {"name" => "bob", "password" => "s3cret"} assert_redirected_to :action => "welcome" assert session["me"] get "logout" assert_template "logout" assert_nil session["me"] end # 自動生成されたコード # Replace this with your real tests. def test_truth assert true end end
C:\InstantRails\rails_apps\wdpress\test\functional>ruby account_controller_test.rb
postやgetのアクションをエミュレートできるらしい。
すげぇな。
あとこんなテストメソッドがあるらしい。
- HTTPのレスポンスの状態をチェック
- redirect先をチェック
- URLとControllerのアクションの対応をチェック
- タグ名や属性地などを元にHTMLをチェック
値の取得先は
などが使用できるみたい。
今回はセッションとインスタンスを利用した例のようです。
今回もエラーが1件インスタンス変数が取得できなかった。
なんでだー。時間ができたら調べてみよう。
この勉強の最後の最後BreakPoint
BreakPointもできるよー。と少ないスペースに記載がありました。
GUIIDEでは目新しい機能ではないが、CUI環境でも使用できるようです。
BreakPointデバッグがしたいが為にGUIIDEを使用している人も多いんじゃなかな?と思っています。
使い方は簡単でした。
- ソースコードに『breakpoint』と一行追加する
- scirpt/serverでサーバーを起動させる
- 別コンソールで script/breakpointerでブレイクポイント機能を実行する
そうするとBreakpointerが待ち状態になって、breakpointがキャッチされると、irbでデバッグできました。
とても便利です。この特集でやったことは便利だと思った数を、へぇ単位換算して何へぇゲットしたか知りたいくらい。
デバッグ例(パラメータとセッションを表示)
No connection to breakpoint service at druby://localhost:42531 (DRb::DRbConnError) Tries to connect will be made every 2 seconds... Executing break point at ./script/../config/../app/controllers/account_controller.rb:24 in `authenti irb(#<AccountController:0x4a22214>):001:0> @params => {"commit"=>"Login", "me"=>{"name"=>"Tom", "password"=>"Tom"}, "action"=>"authenticate", "controll unt"} irb(#<AccountController:0x4a22214>):002:0> @session => #<CGI::Session:0x4a21ddc @session_id="1f7acd798a3292ea3543eeabf0be0515", @dbprot=[#<CGI::Session: 4a21c60 @p=#<PStore:0x4a1bc98 @table=nil, @abort=false, @rdonly=false, @transaction=false, @filename /../config/../tmp/sessions//ruby_sess.9c7014fd142e657e">, @hash={"me"=>#<User:0x4a18a5c @topics=nil, ies=nil, @attributes={"name"=>"Tom", "phone_number"=>"03-1234-0000", "id"=>"1", "password"=>"Tom"}, "flash"=>{}}>], @dbman=#<CGI::Session::PStore:0x4a21c60 @p=#<PStore:0x4a1bc98 @table=nil, @abort=fa ly=false, @transaction=false, @filename="./script/../config/../tmp/sessions//ruby_sess.9c7014fd142e6 sh={"me"=>#<User:0x4a18a5c @topics=nil, @communities=nil, @attributes={"name"=>"Tom", "phone_number" -0000", "id"=>"1", "password"=>"Tom"}, @pet=nil>, "flash"=>{}}>, @data={"me"=>#<User:0x4a18a5c @topi ommunities=nil, @attributes={"name"=>"Tom", "phone_number"=>"03-1234-0000", "id"=>"1", "password"=>" t=nil>, "flash"=>{}}, @new_session=false> irb(#<AccountController:0x4a22214>):003:0> exit Executing break point at ./script/../config/../app/controllers/account_controller.rb:28 in `authenti irb(#<AccountController:0x4a22214>):001:0> @params => {"commit"=>"Login", "me"=>{"name"=>"Tom", "password"=>"Tom"}, "action"=>"authenticate", "controll unt"} irb(#<AccountController:0x4a22214>):002:0> exit Server exited. Closing connection... No connection to breakpoint service at druby://localhost:42531 (DRb::DRbConnError) Tries to connect will be made every 2 seconds...
感想
Railsのひととおりの機能を堪能した感じ。
Railsのさわりで、ここまでできてしまってすごい。自分がすごいと感じちゃ駄目なんですよね(^^;
もっとやってみたい。やりまくりたいと思いました。
なにしろ面白いですし、なんか一つ一つに惹かれる魅力がある。
vimと相性がいい所も好き。
rails.vimの移動系が特に楽で、終盤にインストールしたautocomplpop.vimも役立ってくれました。
違う参考書などで他にも色々とアプリを作ってみたい。