小江戸の勉強会でバリデーションやったよ
小江戸らぐのRails勉強会で今月はvalidationをやりました。
最初に、MVCの意味を簡単に説明して、今回は、MVCの中の
Model部分のバリデーションをやりますよーと説明したけど、省略。
で、バリデーションの意義って?
掲示板のアプリケーションを作ったとき、書き込まれた内容は、データとして保存しますが、
その投稿の中に、名前が無かったり、メールアドレスが不正だったり、文章が無かったりした場合、
データとして保存したくないですよね。
そういうときに、名前は必ず入れてもらったり、メールアドレスが正規表現通りか確認して、
データを保存して良いか判断させる為に実装できます。
と言うわけで、小江戸らぐメンバー表を作ってみましょう。
メンバー表を作るのに必要なデータ定義をみんなで考えて見ました。
まず項目を考える。
番号 | 項目 |
---|---|
1 | 名前 |
2 | 年齢 |
3 | 酒が飲めるか |
4 | 性別 |
5 | 自己紹介 |
6 | メアド |
で、それにカラム名と種類を定義していきました。
性別については、男か女かかける様に、validationの一部の機能を紹介したい為にあえてtext型に*1
番号 | 項目 | カラム名 | 種類 |
---|---|---|---|
1 | 名前 | name | string |
2 | 年齢 | age | integer |
3 | 酒が飲めるか | drink | boolean |
4 | 性別 | sex | string |
5 | 自己紹介 | discription | text |
6 | メアド | string |
と言うわけでカラム名まで決定。
じゃあ、それぞれにバリデーションをかけるのは何にしようかと話し合う。
- 名前とメアドは必須だよねー。
- 性別は男か女かで。
- 年齢18以上とか制限付けてもいい?
- 酒とかもあるし18じゃ怪しいしやっぱ20以上で
- 自己紹介300文字以下で。
- メアドはちゃんとしたメアドじゃないと通さない様に。*2
- メアドはサーバが存在するかのチェックもしたいよねー。
と言うわけで参加者全員で開発開始。
とりあえずよいプロジェクト名思い浮かばなかったのでmember_listとかでプロジェクト作成
$ rails member_list
〜ファイルいっぱい作成〜
$ cd member_list
で、ruby script/generateでモデル作成。
$ ruby script/generate Model Member name:string age:integer drink:boolean \
sex:string discription:text mail:string
で、rake migrateしようとした時にそういえばDB作ってなかったよねーって事でDB作成
$ mysql -u root Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 54 Server version: 5.0.38-Ubuntu_0ubuntu1-log Ubuntu 7.04 distribution Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> create database member_list_development character set utf8;
と、ここで何人かの人の端末上はmysqlじゃなくてsqliteだったようで、
sqlite用にconfig/database.ymlを変えてもらう。
で、いつものようにrake migrate*3
$ rake migrate
ほんとは駄目な書き方で、ちゃんとrake db:migrateってやってくだいね。
とりあえずこれでメンバーテーブルができあがったはずなのでscaffold作成。
$ ruby script/generate scaffold Member
これで、いつもの様にruby script/serverをやって、
http://localhost:3000/membersにアクセスするとscaffoldができあがってるはず。
まだバリデーション組み込んでないので、普通に書き込めます。
最初のバリデーション
とりあえず名前の必須化を行うことに。
validates_presence_of を使って、Memberクラスのnameを必須にしてみましょう。
class Member < ActiveRecord::Base validates_presence_of :name end
そして、http://localhost:3000/members/newから名前を空で作ってみると
[Name can't be blank]と警告が出て作成出来ないようになります。
でも、せっかくなので警告文を変えてあげましょう。って事で:messageを指定してみる。
class Member < ActiveRecord::Base validates_presence_of :name, :message => 'は空白ではいけないのです。' end
これで「Name は空白ではいけないのです。」と警告がでました。
で、mailも空白駄目でしたよね。って事でメールを追加。
class Member < ActiveRecord::Base validates_presence_of :name, :mail, :message => 'は空白ではいけないのです。' end
って書くとなんとmailもnameも警告を出してくれます。
- Name は空白ではいけないのです。
- Mail は空白ではいけないのです。
こんな風に二行。
楽ですよねー。
って説明してると勉強会の時間が無くなってきたので、
一番汎用性のあるvalidationを説明。
def validate って書くと色々できますよー。と
class Member < ActiveRecord::Base validates_presence_of :name, :mail, :message => 'は空白ではいけないのです。' def validate if self.age && self.age < 20 self.errors.add :age,'が20才以下の入会は認めません' return false end end end
こんな感じ。
で、時間が無くなってきたので、validationの解説は別にして、
どこでエラーメッセージを表示してんのー?って話をさせてもらいました。
DRYな感じ
エラーメッセージの前に、app/views/member/new.rhtmlとedit.rhtmlを開いて解説。
new.rhtml
<h1>New member</h1> <% form_tag :action => 'create' do %> <%= render :partial => 'form' %> <%= submit_tag "Create" %> <% end %> <%= link_to 'Back', :action => 'list' %>
edit.rhtml
<h1>Editing member</h1> <% form_tag :action => 'update', :id => @member do %> <%= render :partial => 'form' %> <%= submit_tag 'Edit' %> <% end %> <%= link_to 'Show', :action => 'show', :id => @member %> | <%= link_to 'Back', :action => 'list' %>
新規作成画面も、編集画面も共通の入力フォームは、<%= render :partial => 'form' %>で
_form.rhtmlを呼び出してる事がわかります。
というわけで、実際の項目の画面なんかは共通の部分つかってて、変更時はここだけを変えれば
済むようになってます。
Railsのこういう書き方はDRY的でかなり好きです。
で、実際の_form.rhtmlを開いてみます。
<%= error_messages_for 'member' %> <!--[form:member]--> <p><label for="member_name">Name</label><br/> <%= text_field 'member', 'name' %></p> <p><label for="member_age">Age</label><br/> <%= text_field 'member', 'age' %></p> <p><label for="member_drink">Drink</label><br/> <select id="member_drink" name="member[drink]"><option value="false">False</option><option value="true">True</option></select></p> <p><label for="member_sex">Sex</label><br/> <%= text_field 'member', 'sex' %></p> <p><label for="member_discription">Discription</label><br/> <%= text_area 'member', 'discription' %></p> <p><label for="member_mail">Mail</label><br/> <%= text_field 'member', 'mail' %></p> <!--[eoform:member]-->
で、ここのerror_messages_forでエラーメッセージがあるときだけ表示させてますよーって話をしました。
controllerのクリエイトの部分もあわせて解説。
member_controller.rbのcreateメソッドだけを抜き出すとこんな感じ
1 def create 2 @member = Member.new(params[:member]) 3 if @member.save 4 flash[:notice] = 'Member was successfully created.' 5 redirect_to :action => 'list' 6 else 7 render :action => 'new' 8 end 9 end
2行目で、params[:member]に入ってるデータを元に、@memberにデータを作成し、
3行目で保存にいってます。
で、今回入れたバリデーションなどの理由によってデータの保存に失敗すると、
6行目のelseにいって、newの内容を表示するrender :action => 'new'と実行されています。
その後、@memberが保存する際に発生したエラーをview側のerror_messages_forで表示しています。
で、ここで、参加してた人が、javaだとこういう例外処理を実装するのに時間がかかるけど、
railsはこういうノウハウを誰でも使えるからいいよねーって話をされてました。
わたしも賛成です。
と言う感じで今回の勉強会終了しました。