WEB + DB PRESS 28号の【特集】Ruby on Rails入門に取り組む(3日目)

今日は出掛けていたので空いた時間に本に書いてあるソースコードを読んで復習をしておいた。

解説を読みながらソースコードを読み解く

今回のポイントをまとめてみた。

  1. コントローラーに書いたメソッド名がアクションとなり、アクセスされたURLとマッピングされてアクションが呼び出される。
  2. フィルターでアクションに入る前にコールバック(前処理)を行うことができる。
  3. 前処理フィルターを外したいアクションは、オプションで指定できる。
  4. modelはコントローラーの先頭で宣言する
  5. アクション間で値をやりとり(値の保持)は『flash』という機能で実現できる
  6. 認証チェックはモデルでメソッド定義を書いた
  7. Viewではタグを生成されるメソッドが予め用意されている
  8. エスケープ処理やサニタイジング処理なども用意されている
    1. htmlをエスケープ
    2. SQLサニタイジング


こんな感じだろうか・・・


一個ずつ紐解いていこう。

コントローラーの動き

class AccountController < ApplicationController
  #〜略〜
  def login
    #〜略〜
  end

  def logout
  end

  def welcome
    #〜略〜
  end

  def authenticate
    #〜略〜
  end

private
  # フィルター用メソッド
  def session_authenticate
    #〜略〜
  end
end


基本的にフィルター用のメソッド以外で作成した(一部以外はジェネレーターでできた)メソッドがアクションになるようです。


http://localhost:3000/account/login


にアクセスしたら、Accountコントローラーのloginアクションを呼び出すという感じ。


http://localhost:3000/account/welcome

だったら、Accountコントローラーのwelcomeアクション。以下同文。


なるほど。アクションがなければ、

Unknown action
No action responded to session_authenticate


と表示されるらしい。(フィルターをコメントアウトしたら確認できた)

フィルターの処理

  # アクションを実行する前に呼ぶコールバックを指定する
  before_filter :session_authenticate , :except => %w(login authenticate)

こんな感じで書けばいいらしい。
session_authenticateというPrivateなメソッドを作って指定する。

気になったのが、フィルター起動を除外するオプションで配列を渡しているんだけど、
[ "login" , "authenticate"] ではなく、 %w()という書き方をしているところ。

なぜだろう??ハッシュのキーがシンボルになっているのは「キーワード」を明示的に表現する為に
使っているのはわかるが、それと同じ利用なのかなぁ??(可視性の理由?)

利用するモデルに関して

利用するモデルは先頭で宣言するらしい。


本の端にコラムで、「RailsとDI」に関して記載されていた。

「アクセサ」でDIという形はあえてとらず、「model」という書き方でクラスローダーという形でダイナミックにモデルを利用できるようにしたらしい。
Userクラスのhogehogeメソッドを使うと見せかけて、テスト環境では「Mockクラス」を呼び出し、実行環境では「実クラス」を呼び出す。


ということができるようになっているらしい。


DIをあえて使わず、「more explicit」な方法を考え出したらしい。
Rubyの特性を活かした機能だって。


>コラムに書いてある事が理解できているか不安なので、「らしい」ばかり書いてします。


DHHすごいなぁ。

こういうところが、Railsと他のフレームワークを比較する際に大事な「【なにができるか】ではなく【どうできるか】」の真骨頂なのでしょうか?

class AccountController < ApplicationController
  # モデルとしてUserクラスと使うことを宣言する
  model :user

  # 〜略〜
end

アクション間での値保持


アクション間のメッセージなどの値保持は『flash』という機能で実現できるみたい。

flashに関してちょっと調べてみた。
『Ruby on Rails入門 優しいRailsの育て方』の187ページに載っていた。

flash機能は特別なセッションの利用方法で、保存時期が次回アクションまでに限定されている。
次のアクション実行時に表示するメッセージを渡す、といった場合に便利。

なるほど、authenticateメソッドで認証エラーしたメッセージを、次のloginのアクションに戻ってきて、ビューで表示する時に利用できるってわけかぁ。
flashには2つメソッドが用意されていて、flashの永続性をコントロールできるらしい。

flash[:errMessage1] = "次のアクションまで有効なメッセージ"
flash[:errMessage2] = "こののアクションまで有効なメッセージ"
flash.keep #どちらも次のアクションまで有効になる

便利だ。
機会を作って、実際に利用してみたい。

認証チェックはモデルでメソッド定義

class User < ActiveRecord::Base
  # 〜略〜
  def self.authenticate(name, password)
    find_first([ "name = ? and password = ?", name, password ])
  end
end

本にはサニタイジングの事以外詳しい解説が載っていなくて、なぜselfを書かないといけないのかわからなかった。


舞波本(優しい・・・本の略で使われているみたい)でselfを牽引したところ、

オブジェクト指向的にはメッセージを投げるには、必ずレシーバーが必要になるので、自分自身を表す参照が必要。
それが、"self"。


これが理由なのかなぁ??


findはSQLを実行して、結果のuserオブジェクトを取得するということでしょうか。

findメソッドは「_」で区切って色んな使い方ができるらしい。

find_first()

は1件目のレコードを取得という感じでしょうか。

パラメータにfirstを渡してこんな書き方もできた。

find(:first , :conditions=> [ "name = ? and password = ?", name, password ])

どっちの書き方がお勧めなんだろう…(可視性やメンテナンス性が高いRailsっぽいさとか)

前日、id:secondlifeさんに教えて頂いたRails環境でのconsole確認方法で実行してみた。

ruby server/console
>> User.find(:first , :conditions=> [ "name = ? and password = ?", "foouser", "foouser" ])
=> #<User:0x484a2fc @attributes={"name"=>"foouser", "id"=>"3", "password"=>"foouser"}>
>> User.find(:first , :conditions=> [ "name = ? and password = ?", "foouser", "xxxxxxx" ])
=> nil

で実行した結果、あればオブジェクトを返し、なければnilを返すんですね。なるほど。

メソッドの最後の戻り値はreturnがなければ暗黙的に最後の行の結果がかえるので、コントローラーの
条件文で受け取るってわけですね。

    # 認証メソッドでログイン認証を行う
    if user = User.authenticate(@params["me"]["name"], @params["me"]["password"])
      # 〜略〜
    else
      # 〜略〜
    end


んで、コントローラーでは戻り値を「user」に代入した時の結果をifで条件判断して、処理を切り分けているということかー。
なるほどなるほど。

動作を一個ずつ追うために、こんな例をvimirbっぽいやつで試してみた。(便利すぎる。これ。)

if user = nil
   p "success"
else
   p "fail"
end

まずはエラー系。
全部選択して出力された結果は

"fail"
nil

最後のendでnilを返すってことですね。if文で偽になり結果はelse文を通って、"fail"が出力された。

次は、vim

user = nil


だけ選択して、「Contorl + enter」を押したところ、結果はnil。つまり if nil の結果は偽ってことですね。


今度は、正常系を試す。

if user = "ok"
   p "success"
else
   p "fail"
end

全選択実行では今度は

"success"
nil

表示された。考えていた通りの結果が出てうれしい。「user = "ok"」だけ選択してeval実行の結果は"ok"だから条件文の判定結果は真ってことですね。


よし。
GUI_IDEデバッグ機能をつかわずに処理の流れを追う事に成功。

Viewでのタグを生成

ERBを使って、書く。
formタグはRailsから提供されているのでそれを使えるらしい。

<h1>Account#login</h1>
<p>Find me in app/views/account/login.rhtml</p>

<%= form_tag :action => "authenticate" %>
name: <%= text_field "me", "name" %><br/>
password: <%= password_field "me", "password" %><br/>

<%= submit_tag "Login" %>
<%= end_form_tag %>
<%= h @flash["alert"] %>

仕事ではStrutsでタグライブラリを使って、Viewを書いているので目がなかなか慣れない。


たぶん、rails.vimの機能でViewを便利に書く方法があると思うのですが、surround.vimを拡張した s= で <%= %>をサイドに付加することしか、利用しなかった。(使い方をもっと勉強するぞー)

特にタイポ王なので補完系をもっと覚えたい。

エスケープ処理やサニタイジング処理

これもRailsで用意されているみたい。
SQLで発行した時の、「?」がそれにあたる。使いやすい感じ。>サニタイジング

エスケープも簡単で、hっていうメソッドが用意されていて利用できる。
括弧が省略されているけど、実際は

<%= h(@flash["alert"]) %>

と同じなんですよね。括弧省略すると見やすいなー。


perlを使っている時も、pushなどでは括弧は省略していたので、それほど戸惑いはないなぁ。


これで、第二章完了!

振り返りとまとめ

  • 第二章の振り返り(KPT法使うよ)とまとめ。

ぷちKPT

  • KEEP【良かった事、続けていきたい事】
    • コントローラーの役割がわかった
    • バリデーションの使い方がわかった
    • リファレンス本(舞波本)を利用し、わからない所を補足できた。
    • つまづいたところもあったけど、コード全体を把握できた。
    • ロジック処理のソースコードを解析できた
    • vimirbのみでCUI環境のみで取り組みができた
    • 勉強できる環境と、意気込みを整えられた
    • はてなDiaryに失敗と反省を書くことが引き続きできた(見える化
  • PROBLEM【悪かったこと、改善したい事】
    • タイポを減らしたい
    • 補完機能をもっと利用したい
    • もっと文章をわかりやすくまとめたい。
    • rails.vimの機能をあまり引き出せなかった
  • TRY【今後取り込みたいこと】
    • rails.vimの機能をもっと使いたい(常にrails.vimで楽できないかを意識する)
    • 見える化、わからない時はリファレンス本で調べる事を続ける

まとめ