Postモデルを作ろう - satococoa/api-tutorial GitHub Wiki
Post モデルをジェネレート
以下のコマンドで名前、タイトル、本文の3つの項目があるモデルを作ります。
$ rails g model post name title body:text
$ rake db:migrate
管理画面にアクセスすると、既に Post モデルの操作が行えるはずです。
バリデーションを追加
このままだと、全項目を空でも保存できてしまいますので、以下のような制限を加えます。
- name, title 属性は空ではいけない
- name は 3 文字以上、100 文字以下とする
- title も 3 文字以上、100 文字以下とする
テスト (spec) を書く
テストを実行してみます。rake spec
と打つと以下のようになります。
$ rake spec
[RailsAdmin] RailsAdmin initialization disabled by default. Pass SKIP_RAILS_ADMIN_INITIALIZER=false if you need it.
/Users/ebisawa/.rbenv/versions/2.0.0-p247/bin/ruby -S rspec ./spec/models/post_spec.rb
*
Pending:
Post add some examples to (or delete) /Users/ebisawa/dev/ruby-rails-study/bbs/spec/models/post_spec.rb
# No reason given
# ./spec/models/post_spec.rb:4
Finished in 0.00025 seconds
1 example, 0 failures, 1 pending
Randomized with seed 53327
今は pending (保留) のテストがひとつあるだけです。まずは必要な仕様を spec という形でコードに表します。
spec/models/post_spec.rb を以下のように変更してください。
require 'spec_helper'
describe Post do
describe '#valid?' do
it '全属性が正しい場合はtrue' do
post = Post.new(name: 'foo', title: 'bar', body: 'bazbazbazbaz')
expect(post.valid?).to be_true
end
it 'nameが空の場合はfalse' do
post = Post.new(name: '', title: 'bar', body: 'bazbazbazbaz')
expect(post.valid?).not_to be_true
end
end
end
この状態で rake spec
すると、当然テストは失敗するはずです。
$ rake spec (post-model)[~/dev/ruby-rails-study/bbs]
[RailsAdmin] RailsAdmin initialization disabled by default. Pass SKIP_RAILS_ADMIN_INITIALIZER=false if you need it.
/Users/ebisawa/.rbenv/versions/2.0.0-p247/bin/ruby -S rspec ./spec/models/post_spec.rb
.F
Failures:
1) Post#valid? nameが空の場合はfalse
Failure/Error: expect(post.valid?).not_to be_true
expected: non-true value
got: true
# ./spec/models/post_spec.rb:12:in `block (3 levels) in <top (required)>'
Finished in 0.01537 seconds
2 examples, 1 failure
Failed examples:
rspec ./spec/models/post_spec.rb:10 # Post#valid? nameが空の場合はfalse
Randomized with seed 51925
では、無事にテストが失敗したので name が空のときに valid?
が false
になるように、モデルにバリデーションを実装します。
実装を書く
app/models/post.rb を編集してください。
class Post < ActiveRecord::Base
validates :name, presence: true # この一行を追加
end
これで再度テストを実行すれば、正しく pass するはずです。
$ rake spec (post-model)[~/dev/ruby-rails-study/bbs]
[RailsAdmin] RailsAdmin initialization disabled by default. Pass SKIP_RAILS_ADMIN_INITIALIZER=false if you need it.
/Users/ebisawa/.rbenv/versions/2.0.0-p247/bin/ruby -S rspec ./spec/models/post_spec.rb
..
Finished in 0.02117 seconds
2 examples, 0 failures
Randomized with seed 8186
リファクタリング
実装コードはこれ以上簡略化しようがないので、テストコードをリファクタリングします。
テストデータの作成を簡単にしてくれる FactoryGirl とランダムな値を生成してくれる Forgery を組み合わせて使います。
- FactoryGirl の使い方は [https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md] 参照
- Forgery の使い方は [http://rubydoc.info/gems/forgery/frames] 参照
spec/factories/posts.rb を編集 (バリデーションに通る正しいテストデータにしておきます)
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :post do
title { Forgery(:basic).text(at_least: 3, at_most: 100) }
name { Forgery(:basic).text(at_least: 3, at_most: 100) }
body { Forgery(:lorem_ipsum).words(10) }
end
end
spec/models/post_spec.rb を以下のようにします。
require 'spec_helper'
describe Post do
describe '#valid?' do
context '全ての属性が正しいとき' do
subject(:post) { FactoryGirl.build(:post) }
specify { expect(post).to be_valid }
end
context 'nameが空のとき' do
subject(:post) { FactoryGirl.build(:post, name: '') }
specify { expect(post).not_to be_valid }
end
end
end
rake spec
を実行し、ちゃんとテストに pass していることを確認してください。
続きは自分でやってみてください
あとは"テストを書く、実装を書く、リファクタリングする"の繰り返しです。 これを TDD (Test Driven Development) あるいは BDD (Behavior Driven Development) といいます。