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) といいます。