Ruby on RailsチュートリアルのサンプルのRails 4対応作業補足

Ruby on Railsチュートリアルのサンプルアプリ sample_appのRails 4対応作業。

$ bundle exec rspec spec/models/user_spec.rb

で、エラー、

/usr/local/rvm/gems/ruby-2.0.0-p353@global/gems/selenium-webdriver-2.0.0/lib/selenium/webdriver/common/zipper.rb:1:in `require’: cannot load such file — zip/zip (LoadError)

が出る。ググると、http://www.workabroad.jp/posts/1095 が引っかかる。selenium-webdriver gemのバージョンを新しいのに上げるといいらしい。ところで、Everyday Rails RSpecによるテスト入門では、JavaScriptを含む複雑なwebアプリ上の操作をFirefox経由で行うときに、Seleniumを使うが、Firefoxが頻繁にアップデートするため、Seleniumを使ったテストが動かなくなることが多く、selenium-webdriver gemは最新版にアップデートした方がいいとのこと。そこで、それを、2.40.0にあげたら、エラーはなくなった。テストは失敗するが。

$ bundle exec rspec spec/models/user_spec.rb

テストが失敗するが、Factoryが登録されていないと言われるので、factories.rbを規定の場所にコピー。

再度、

$ bundle exec rspec spec/models/user_spec.rb

チュートリアルによると、”protected_attributes gem (リスト12.1) の動作がRails 3.2の「アクセス可能な属性」と異なっているため、マスアサインメントのセキュリティエラーをテストするコードは4.0では動作しなくなりました。”ということなので、失敗しているテストを削除。再度、テスト。OK。

同様に、micropost、relationshipモデルのテストの失敗する部分も、削除する。

user_pages_spec.rb の修正では、

it { should have_selector(‘title’, text: ‘All users’) }

it { should have_title(‘All users’) }

などと置き換えないといけない。hav_titleメソッドで、text: を書くとダメ。

チュートリアルの、Rails 4対応の説明の通りにやると、これで全テストが通るのだけど、app/asssetsの内容をコピーすると、

undefined method `environment’ for nil:NilClass when importing Bootstrap

と言われる。ググると、http://stackoverflow.com/questions/22392862/undefined-method-environment-for-nilnilclass-when-importing-bootstrap が引っかかり、sass-railsが4.0.0だとダメということで、4.0.2に変更したら、テストが通るようになった。

Rails 4.0.0、RSpec、Capybara使用プロジェクト向けGemfile

Ruby on Rails チュートリアルの、Ruby on Rails 4向けの記事を読んでいます。記事に書いてあるGemfileだと、依存関係がおかしく、buundle installでエラーになります。うまくいくGemfileを示します。

source ‘https://rubygems.org’
ruby ‘2.0.0’

gem ‘rails’, ‘4.0.0’
gem ‘bootstrap-sass’, ‘2.3.2.0’
gem ‘bcrypt-ruby’, ‘3.0.1’
gem ‘faker’, ‘1.1.2’
gem ‘will_paginate’, ‘3.0.4’
gem ‘bootstrap-will_paginate’, ‘0.0.9’

group :development, :test do
gem ‘sqlite3’, ‘1.3.7’
gem ‘rspec-rails’, ‘2.13.1’
# The following optional lines are part of the advanced setup.
# gem ‘guard-rspec’, ‘2.5.0’
# gem ‘spork-rails’, github: ‘sporkrb/spork-rails’
# gem ‘guard-spork’, ‘1.5.0’
# gem ‘childprocess’, ‘0.3.6’
end

group :test do
gem ‘selenium-webdriver’, ‘2.0.0’
gem ‘capybara’, ‘2.1.0’
gem ‘factory_girl_rails’, ‘4.2.0’
gem ‘cucumber-rails’, ‘1.3.0’, :require => false
gem ‘database_cleaner’, github: ‘bmabey/database_cleaner’

# Uncomment this line on OS X.
# gem ‘growl’, ‘1.0.3’

# Uncomment these lines on Linux.
# gem ‘libnotify’, ‘0.8.0’

# Uncomment these lines on Windows.
# gem ‘rb-notifu’, ‘0.0.4’
# gem ‘win32console’, ‘1.3.2’
end

#gem ‘sass-rails’, ‘4.0.2’
gem ‘sass-rails’, ‘4.0.0’
gem ‘railties’, ‘4.0.0’
gem ‘uglifier’, ‘2.1.1’
gem ‘coffee-rails’, ‘4.0.0’
gem ‘jquery-rails’, ‘2.2.1’
gem ‘turbolinks’, ‘1.1.1’
gem ‘jbuilder’, ‘1.0.2’

group :doc do
gem ‘sdoc’, ‘0.3.20’, require: false
end

group :production do
gem ‘pg’, ‘0.15.1’
gem ‘rails_12factor’, ‘0.0.2’
end

gem ‘protected_attributes’

gem ‘execjs’
gem ‘therubyracer’

基礎Ruby on Rails改訂新版のサンプルアプリでFakerを使ってみた

最近、Everyday Rails – RSpecによるRailsテスト入門という電子書籍を読んで、RSpecでテストコードを書くことに取り組んでいます。練習として、基礎Ruby on Rails改訂新板のサンプルアプリにRSpecでテストコードを書きました。Memberクラスは、次のようなバリデーションがあります。

class Member < ActiveRecord::Base
  include EmailAddressChecker

  attr_accessible :number, :name, :full_name, :email, :birthday, :gender, :administrator
  validates :number, presence: true,
            numericality:  { only_integer: true,
            greater_than: 0, less_than: 100, allow_blank: true },
            uniqueness: true
  validates :name, presence: true,
            format: { with: /\A&#91;A-Za-z&#93;\w*\z/, allow_blank: true,
                      message: :invalid_member_name },
            length:  { minimum:  2, maximum:  20, allow_blank: true },
            uniqueness: { case_sensitive: false }
  validates :full_name, length: { maximum:  20 }
  validate :check_email
  validates :gender, inclusion: { in: 0..1 }

  private
    def check_email
      if email.present?
        errors.add(:email, :invalid) unless well_formed_as_email_address(email)
      end
    end

    class << self
      def search(query)
        rel = order("number")
        if query.present?
          rel = rel.where("name LIKE ? OR full_name LIKE ?",
                        "%#{query}%", "%#{query}%")
        end
        rel
      end
    end
end
&#91;/ruby&#93;

FactoryGirl gemとFaker gemを使って、テストデータを生成しました。

&#91;ruby&#93;
require 'faker'

FactoryGirl.define do
  factory :member do
    sequence(:number) { |n| n unless n > 99 }
    name {
      name = Faker::Name.first_name.slice!(0, 19).capitalize
      name if name.length >= 2
    }
    full_name { Faker::Name.name.slice!(0, 19) }
    email {Faker::Internet.email }
    birthday "1981-12-01"
    gender { Faker::Number.number(1).to_i % 2 }
    administrator false

    factory :invalid_member do
      name nil
    end
  end
end

この場合、テストコードを書くと、英語環境ではテストは失敗しません。ところが、i18nで国際化して、日本語環境でテストすると、fakerは国際化に対応しているようで、nameが日本語になったり、emailが不正な表現になって失敗するようになります。バリデーションでは、nameは英字で始まり、英数字からならないとダメだからです。しかし、full_nameについては、日本語のデータが生成されるようにしたいです。fakerのサイトページを見ると、Faker::Config.locale でロケールをスイッチできるようです。そこで、次のファイルを使ってテストデータを生成するようにしました。

require 'faker'

FactoryGirl.define do
  factory :member do
    sequence(:number) { |n| n unless n > 99 }
    name {
      Faker::Config.locale = 'en-us'
      name = Faker::Name.first_name.slice!(0, 19).capitalize
      name if name.length >= 2
    }
    full_name {
      Faker::Config.locale = 'ja'
      Faker::Name.name.slice!(0, 19)
    }
    email {
      Faker::Config.locale = 'en-us'
      Faker::Internet.email
    }
    birthday "1981-12-01"
    gender { Faker::Number.number(1).to_i % 2 }
    administrator false

    factory :invalid_member do
      name nil
    end
  end
end

Faker::Config.locale でロケールをスイッチすると、その後は設定したロケールのままになると期待したのですが、そのようにはならないようで、各フィールドごとにロケールをスイッチしないとダメでした。このテストデータを使用すると、テストが通るようになりました。