浜松Rails3道場 其の弐 Model編

Preview:

Citation preview

浜松Rails3道場其の弐 Model編

Hamamatsurb#5 2011.07.13 @mackato

2011年7月13日水曜日

浜松Rails3道場の心得

習うより慣れろ

理論より実用

未知を恐れない

2011年7月13日水曜日

実際にRailsアプリを作ってみる

Wiki

全5回位で

2011年7月13日水曜日

Wikiの仕様

ページの編集と削除ができる

ページにコメントできる

ページの表示ができる

2011年7月13日水曜日

Wikiの仕様

ページの編集履歴が確認できる

ユーザー認証ができる

2011年7月13日水曜日

Wikiの仕様

ページの一覧が表示できる

2011年7月13日水曜日

Wikiの仕様ページが作成できる

2011年7月13日水曜日

開発環境

Ruby Version 1.9.2

Rails Version 3.0.7

.rvmrcrvm ruby-1.9.2-p180@rails-3_0_7

2011年7月13日水曜日

サンプルコードの取得GitHubから其の弐用のコードを取得

git clone git://github.com/hamamatsu-rb/rails3dojo.git

git checkout -b working 2-model_pre

開始地点のタグ作業ブランチ

2011年7月13日水曜日

テスト環境の準備FactoryGirl(テストデータ作成)、Spork(テスト高速化)の導入

Gemfileに追加group :test do gem "factory_girl_rails" gem "spork", ">= 0.9.0.rc2"end

.rspecに追加--drb

spork --bootstrap

Sporkの初期化

2011年7月13日水曜日

モデルの作成今回開発するWikiで必要なモデル

User: Wikiの編集をおこなうユーザーPage: タイトルや本文をもつWikiページComment: Pageに対するコメントHistory: Pageの更新履歴

2011年7月13日水曜日

Userモデルの作成Wikiの編集をおこなうユーザー

rails g model user name:string

rake db:migrate

2011年7月13日水曜日

UserのFactoryspec/factories.rb

Factory.define :user do ¦f¦ f.name "bob"end

spec/spec_helper.rbdef create_user(params = {}) Factory.create(:user, params)end

def build_user(params = {}) Factory.build(:user, params)end

2011年7月13日水曜日

UserのSpecspec/models/user_spec.rb

describe User do describe "#name" do it "必須" do user = build_user(:name => "") user.should_not be_valid end ... end describe "#find_or_create_by_name" do context "同じ名前のユーザーが存在する場合" do it "存在しているユーザーを取得する" do ... end end context "同じ名前のユーザーが存在しない場合" do it "新しいユーザーを作成する" do ... end end endend

クラス

メソッド

コンテキスト

スペック

2011年7月13日水曜日

Userクラスapp/models/user.rb

class User < ActiveRecord::Base validates :name, :presence => true, :length => { :maximum => 50 }, :uniqueness => trueend

SexyValidation!

validates_presence_of :namevalidates_length_of :name, :maximum => 50validates_uniqueness_of :name

Legacy Style Validation

2011年7月13日水曜日

テスト実行bundle exec rspec spec/models/user_spec.rb

User #name 必須 50文字以内 重複不可 #find_or_create_by_name 同じ名前のユーザーが存在する場合 存在しているユーザーを取得する 同じ名前のユーザーが存在しない場合 新しいユーザーを作成する

2011年7月13日水曜日

Pageモデルの作成タイトルや本文をもつWikiページ

rails g model page title:string body:text \ user_id:integer

rake db:migrate

2011年7月13日水曜日

PageのFactoryspec/factories.rb

spec/spec_helper.rbdef create_page(params = {}) Factory.create(:page, params)end

def build_page(params = {}) Factory.build(:page, params)end

Factory.sequence :page_title do ¦n¦ "Page #{n}"end

Factory.define :page do ¦f¦ f.title { Factory.next(:page_title) } f.body "Lorem ipsum dolor sit amet, ..." f.association :userend

2011年7月13日水曜日

PageのSpecspec/models/page_spec.rb(抜粋)

describe Page describe "#user" it "ページを作成したユーザー" it "必須" describe "#title" it "必須" it "255文字以内" it "重複不可" describe "#body" it "文字数は実質無制限" describe "#recent" it "最新の10件" it "作成日の降順でソート"

2011年7月13日水曜日

Pageクラスapp/models/page.rb

class Page < ActiveRecord::Base belongs_to :user

validates :user, :presence => true validates :title, :presence => true, :length => { :maximum => 255 }, :uniqueness => true scope :recent, limit(10).order("created_at DESC")end

2011年7月13日水曜日

Commentモデルの作成Pageに対するコメント

rails g model comment body:text \ page_id:integer user_id:integer

rake db:migrate

2011年7月13日水曜日

CommentのFactoryspec/factories.rb

spec/spec_helper.rbdef create_comment(params = {}) Factory.create(:comment, params)end

def build_comment(params = {}) Factory.build(:comment, params)end

Factory.define :comment do ¦f¦ f.body "Lorem ipsum dolor sit amet, ..." f.association :page f.user { ¦c¦ c.page.user }end

2011年7月13日水曜日

CommentのSpecspec/models/comment_spec.rb(抜粋)

describe Comment describe "#page" it "コメント対象のページ" it "必須"

describe "#user" it "コメントを投稿したユーザー" it "必須"

describe "#body" it "必須" it "1000文字以内"

2011年7月13日水曜日

Commentクラスapp/models/comment.rb

class Comment < ActiveRecord::Base belongs_to :page belongs_to :user validates :page, :presence => true validates :user, :presence => true validates :body, :presence => true, :length => { :maximum => 1000 }end

2011年7月13日水曜日

PageにCommentへの関連を追加

spec/models/page_spec.rb (抜粋)

app/models/page.rb

has_many :comments

describe Page ... describe "#comments" it "ページへのコメント" it "作成日の昇順でソート" it "Pageと一緒に全て削除"

2011年7月13日水曜日

Historyモデルの作成Pageの更新履歴

rails g model history \page_id:integer user_id:integer

rake db:migrate

2011年7月13日水曜日

HistoryのFactoryspec/factories.rb

spec/spec_helper.rbdef create_history(params = {}) Factory.create(:history, params)end

def build_history(params = {}) Factory.build(:history, params)end

Factory.define :history do ¦f¦ f.association :page f.user { ¦c¦ c.page.user }end

2011年7月13日水曜日

HistoryのSpecspec/models/history_spec.rb

# -*- coding: utf-8 -*-require 'spec_helper'

describe History do describe "#page" do it "履歴の対象のページ" do create_history.page.should be end end describe "#user" do it "履歴を更新したユーザー" do create_history.user.should be end endend

2011年7月13日水曜日

Historyクラスapp/models/history.rb

class History < ActiveRecord::Base belongs_to :page belongs_to :userend

2011年7月13日水曜日

PageにHistoryへの関連を追加spec/models/page_spec.rb (抜粋)

app/models/page.rb

has_many :histories

describe Page ... describe "#histories" it "ページの更新履歴" it "作成日の降順でソート" it "Pageと一緒に全て削除"

2011年7月13日水曜日

Pageの更新時に履歴を追加するspec/models/page_spec.rb (抜粋)

app/models/page.rb

describe Page ... describe "#save_by_user" it "保存の成否を返す" it "Historyを1つ追加"

def save_by_user(updater) if self.save self.histories.create(:user => updater) true else false end end

2011年7月13日水曜日

今回の開発はここまで

git checkout 2-model

作業内容をmasterにマージgit checkout mastergit merge working

作業後のコードはGitHubにありますgit clone git://github.com/hamamatsu-rb/rails3dojo.git

git branch -d working

2011年7月13日水曜日

More Rails Models

2011年7月13日水曜日

データベース構造の管理

Migrations

class CreatePages < ActiveRecord::Migration def self.up create_table :pages do ¦t¦ t.string :title t.text :body t.integer :user_id

t.timestamps end end

def self.down drop_table :pages endend

rake db:migrate [VERSION=YY..]rake db:rollback [STEP=N]rake db:migrate:redo [STEP=N]

db/migrate/20110712154821_create_pages.rbpageテーブル作成

pageテーブル削除

フィールド定義

2011年7月13日水曜日

データ検証

Validations

Validation Helpers vs SexyValidation

validates_acceptance_of :terms_of_servicevalidates_associated :friendsvalidates_confirmation_of :passwordvalidates_exclusion_of :password, :in => %w(0000)validates_format_of :login, :with => /^[a-z]+/ivalidates_inclusion_of :answer, :in => %w(Y N)validates_length_of :password, :in => 4..8validates_numericality_of :age, :only_integer => truevalidates_presence_of :login, :passwordvalidates_uniqueness_of :login

validates :terms_of_service, :acceptance => truevalidates :password, :confirmation => true, :exclusion => { :in => %w(0000) }, :length => { :in => 4..8 }, :presence => truevalidates :login, :format => { :with => /^[a-z]+/i }, :presence => true, :uniqueness => truevalidates :answer, :inclusion => { :in => %w(Y N) }

2011年7月13日水曜日

データ関連

Associations

class  Order  <  ActiveRecord::Base    belongs_to  :customerend

class  Supplier  <  ActiveRecord::Base    has_one  :accountend

The belongs_to Association

The has_one Association

The has_many Association

class  Customer  <  ActiveRecord::Base    has_many  :ordersend

The has_many :through Association

class  Physician  <  ActiveRecord::Base    has_many  :appointments    has_many  :patients,  :through  =>  :appointmentsend  class  Appointment  <  ActiveRecord::Base    belongs_to  :physician    belongs_to  :patientend  class  Patient  <  ActiveRecord::Base    has_many  :appointments    has_many  :physicians,  :through  =>  :appointmentsend

参考: Active Record Associations: http://bit.ly/n3exu9

2011年7月13日水曜日

データ検索

Query

Active Record Query Interface: http://bit.ly/qaeazJ

Finder methods

• where• select• group• order• limit• offset• joins• includes• lock• readonly• from• having

Retrieving a Single Object

Page.find(10)Page.where(:title => "Title 1").firstPage.last

Retrieving Multiple Objects

Page.find(1, 10)Page.all.each do ¦variable¦ page.save!end

Calculations

Page.limit(10).count #=> 11Page.limit(10).all.count #=> 10

遅延評価に注意

2011年7月13日水曜日

ActiveRecord覚えること大杉

結論

2011年7月13日水曜日

実演

2011年7月13日水曜日

Q&A

2011年7月13日水曜日

多分、ActionController

次回予告

2011年7月13日水曜日

Recommended