はじめに
まずは、前回のKPTのTRYを確認
- そこそこな時間集中して取り組むので飲み物やおやつを側におきたい
- 紅茶と味カレーを用意した。HHK Lite2は周りのスペースを有効に使えていい感じ。
- rails.vimの機能をもっと使いたい(常にrails.vimで楽できないかを意識する)
- よし、意識した。
- ジェネレーターを多用したい
- 使うでしょう。
- ソースコードの中を解析したい
- ちょっと優先度を下げて、次回以降か勉強会で実施したい。
- やっている最中の事を文章に書き出すと自分の考えていることや反省点がわかったので続けていきたい。(見える化)
- 今、書き始めた。
チートシートを用意して、本を開いた。
第二章 Railsの構成と仕組みについて
Railsはフルスタックフレームワーク。
Javaでよくある複数フレームワークやライブラリの組み合わせとは異なる。
主なRailsに付属するモジュールは下記の5つだとのこと。
- ActiveRecord
- ActionPack
- ActiveSupport
- ActionMailer
- ActiveWebService
はじめの4つはよく聞いたり、役目はわかるけど、最後のActiveWebServiceがよく知らない。
解説では
Webサービス,主にXML-RPCを行うために使うも
のです.RailsからWebサービスを利用する場合には,
このライブラリを使うことが推奨されています
だって。AjaxとかPrototype.jsに使用するのだろうか。ActiveWebServiceは実際に使用する時に覚える事にする。
あと、RailsのbreakpointはdRubyの分散環境が利用されているらしい。
仕組みは於いておいて、利用してみたいなぁ。
さっそく簡単なアプリを作成することに。
機能は2つ。
- 会員ログイン
- 会員登録
面白そう。
データベースの準備
んー。新しくrailsコマンドでアプリ作ってくださいとか書いていないけど、昨日のdemoとは別に作ろう。
rails wdpress
vimでdatabase.ymlを編集する。
触れられてはいないが、開発用と運用用のスキーマを同じものでやるらしい。>database.ymlを見る限りでは*1
development: adapter: mysql database: wdpress username: root password: host: localhost test: adapter: mysql database: wdpress_test username: root password: host: localhost production: adapter: mysql database: wdpress username: root password: host: localhost
PDFからSQLをコピーして中を確認し、スキーマとテーブルを作成した。
create table users (
id int unsigned not null auto_increment,
name varchar(20) not null,
password varchar(20) not null,
primary key (id)
);
大事なこと(規約)
- 主キーはidかつオートナンバー
- テーブル名は複数形
テーブル名の複数形を知るには、gorouさんのrails2u.comで変換してくれるCGIがあったのですが消えていた。
確か、昨日rails2u.comのサーバー構築し直したってRSSみた気がする…
http://subtech.g.hatena.ne.jp/secondlife/20071027/1193411269
微妙な *.rails2u.com のやつは全部止めてみた。
やっぱり。
RailsがActiveSupportで拡張*2したStringクラスのpluralizeメソッドが同じ役割をしてくれると思ったので、irbで確かめてみる。
※追記:server/consoleの方が便利*3
最初にgemsとactiverecordをロードし忘れてエラーってしまった。
やりなおしたら、できた。
C:\InstantRails\rails_apps>irb -r rubygems -r active_support irb(main):001:0> "user".pluralize => "users" irb(main):002:0> "person".pluralize => "people" irb(main):003:0> exit
これをvimのirbっぽいやつでやれたら便利だろうなぁ。
それはまた今後試してみる。
scaffoldで会員登録機能を作る
scafforld発射。
ruby script/generate scaffold user
exists app/controllers/ exists app/helpers/ exists app/views/users exists app/views/layouts/ exists test/functional/ dependency model exists app/models/ exists test/unit/ exists test/fixtures/ identical app/models/user.rb identical test/unit/user_test.rb identical test/fixtures/users.yml create app/views/users/_form.rhtml create app/views/users/list.rhtml create app/views/users/show.rhtml create app/views/users/new.rhtml create app/views/users/edit.rhtml create app/controllers/users_controller.rb create test/functional/users_controller_test.rb create app/helpers/users_helper.rb create app/views/layouts/users.rhtml create public/stylesheets/scaffold.css
一回目は失敗した。なぜかと言うと、database.ymlを保存し忘れていたから。
とほほ…
: w
次はvalidation
会員情報のvalidationを設定するらしい。
- アカウントを一意にする
- アカウントの文字列長を制限
- パスワードの文字列長を制限
ここでもrails.vimを使って、モデルにvalidationを書く。
strutsではActionForm名をvalidation.xmlでvalidationを設定したが、railsではモデルに書くんですね。
結構これ、ポイントだよなー。
strutsではvalidation.xmlを複数に分けて、includeして分散化することあるけど、モデルごとに集約できれば、異なる人が
validationが作成する時にActionFormが異なっていて、モデルで微妙に作成しているvalidationが違うよ。ってことなくなるなぁ。
class User < ActiveRecord::Base validate_uniqueness_of :name , :on => :create validate_length_of :name , :within => 3..40 validate_length_of :password , :within => 5..40 end
validationを追記した。*4
※これはタイポしたまんまの例です。
バリデーションルールも調べた。
『Ruby on Rails入門 優しいRailsの育て方』の77ページに載っていた。
- validates_uniqueness_of
- カラムの値がユニークである事を検証する(一意性)
- オプション1 :scope 指定されたカラムの値が同じオブジェクト間のみユニークであることを保証する
- オプション2 :case_sensitive 大文字小文字を無視したい場合に利用。falseにする。
- validates_length_of
- カラムの値が指定された長さであることを検証する(長さ)
- オプション 「最大値」「最小値」「長さ」「範囲」指定ができるらしい。なるほど今回は範囲を使うわけね。
Railsセミナーで増井さん(masuidrive)が言っていた「Rubyらしい書き方。RailsはRubyの特性を活かしている」っていうのは
こういう書き方のことなんだろうか。
validates_length_of :password , :within => 5..40
Rangeでパラメータをハッシュにセットしているが、可視性がやたらよくて、わかりやすい。
日本語っぽく、前から順に読んでみた。
「長さチェックバリデーションを使って、パスワードカラムを範囲が5〜40のものチェック」
これで、CRUD&Validationができているはずなので、動作確認
動作確認と修正
起動する
ruby script/server
アクセスしたらエラーった。
http://localhost:3000/users
NoMethodError in UsersController#index undefined method `validate_uniqueness_of' for User:Class
タイポしたかなぁ。確認する
わかった。「s」が抜けている。
正しくは
class User < ActiveRecord::Base validates_uniqueness_of :name , :on => :create validates_length_of :name , :within => 3..40 validates_length_of :password , :within => 5..40 end
よし、動いた。動作確認おーけー。
ログイン機能を作る
ログイン機能も簡単に作れるようです。
Accountコントローラーをジェネレーターで作るらしい。
まずは、ジェネレーターで作ってから、解説を読みながらソースを読むことにする。
ruby script/generate controller Account login logout welcome
exists app/controllers/ exists app/helpers/ create app/views/account exists test/functional/ create app/controllers/account_controller.rb create test/functional/account_controller_test.rb create app/helpers/account_helper.rb create app/views/account/login.rhtml create app/views/account/logout.rhtml create app/views/account/welcome.rhtml
コントローラージェネレーターを使って、Accountコントローラーを作成しAccountコントローラーに結びつく、
「login」「logout」「welcome」ビューを作成するということらしい。
- ジェネレータのパラメータの注意
- コントローラー名は大文字で始める
- ビューは小文字で
コントローラーにロジックを書く。
:Rcontroller account
ジェネレータで生成されたコントローラーのソースコード
class AccountController < ApplicationController def login end def logout end def welcome end end
よし、書いた。
タイポしていなければ、OKだと思う。*5
自分なりに、コメントもつけてみた。コメントは後で変更するするかもしれない。
ロジックを追加したコントローラーのソースコード
class AccountController < ApplicationController # モデルとしてUserクラスと使うことを宣言する model :user # アクションを実行する前に呼ぶコールバックを指定する before_filter :session_authenticate , :except => %w(login authenticate) def login end def logout # セッションのログイン情報を消す @session ["me"] = nil end def welcome # Viewのwelcomeで参照して使用できるようにする為に # sessionに格納されている、ログイン情報をインスタンス変数のmeにセットする @me = @session["me"] end def authenticate # POSTで受けとった、「ログイン名」と「ログインパスワード」をUserモデルで # 認証メソッドでログイン認証を行う if user = User.authenticate(@params["me"]["name"], @params["me"]["password"]) # ログイン情報が一致したら、セッションにログイン情報(userオブジェクト)をセットして @session["me"] = user # welcomeページへ遷移する redirect_to :action => "welcome" else # ログイン情報が一致しなければエラーメッセージをセットして flash["alert"] = "Login failed!" # ログイン画面へ遷移する(再認証を行う) redirect_to :action => "login" end end private #------------------------------------------- # セッションのログイン情報の存在チェック #------------------------------------------- def session_authenticate # セッションにログイン情報がセットされていない場合は unless @session["me"] # ログインアクションへリダイレクトする redirect_to :action => "login" # 失敗したら以降のactionは呼ばれないようにする為に、最後にfalseをセットする false end end end
このままの勢いで、Viewを書く。
まずはlogin.rhtml
<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"] %>
続いてwelcome.rhtml
<h1>Account#welcome</h1> <p>Find me in app/views/account/welcome.rhtml</p> welcome, <%= h @me.name %>!
最後にモデルにログイン認証チェックのメソッドを作る
class User < ActiveRecord::Base validates_uniqueness_of :name , :on => :create validates_length_of :name , :within => 3..40 validates_length_of :password , :within => 5..40 def self.authenticate(name, password) find_first([ "name = ? and password = ?", name, password ]) end end
よし、これで全部か??
見落としていないだろうか・・・
これでタイポがなかったら、自分へのご褒美として「ガリガリ君」を買うよ。
動作確認
ruby script/server
そして、ログインページへアクセスする。
コントローラー51行目でエラーが起きた。
やってしまった。「.」と「,」を打ち間違えた…
ご褒美はなしだな。
修正したら、ビューは表示された。
よし、ログイン認証・ログアウトもできた。
- ログイン画面
- ログイン後Welcome画面
- ログアウト画面(ログアウト処理が行われた)
解説を読みながらソースコードを読み解く
続きは明日にしようと・・・