『RailsとiPhoneではじめるアプリケーション開発』を進める時の注意点・ハマったこと Chapter 07

引き続き、『RailsiPhoneではじめるアプリケーション開発』を進めてみようと思います。

RailsとiPhoneではじめるアプリケーション開発

RailsとiPhoneではじめるアプリケーション開発

Chapter 01 -> 03
『RailsとiPhoneではじめるアプリケーション開発』を進める時の注意点・ハマったこと Chapter 03まで - diceK66のブログ
Chapter 04 -> 06
『RailsとiPhoneではじめるアプリケーション開発』を進める時の注意点・ハマったこと Chapter 06まで - diceK66のブログ

重要事項

エラーが起きたらコンソールをじっくり読みましょう

特に自分が作成or編集したファイルがログに出てきたら、必ず正しくソースが書けているか等をチェックしましょう

p.169 rspecのテストが通らない

rspec spec/controllers/travel_controller_spec.rb

これを実行すると以下のようなエラーがでました。

1) TravelController#index should show all data when user do not logged in
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  2) TravelController#index should show all data when user logged in
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  3) TravelController#index shoud show user data when requested with user_id
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  4) TravelController#new should access to new, does not work without a signed in user
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  5) TravelController#new should assign as new travel as @travel when sign in
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  6) TravelController#edit access to edit, assigns not work without a signed in user
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  7) TravelController#edit assign as edit travel as @travel when sign in
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  8) TravelController#edit access to edit, should not work when sign in as another user
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

  9) TravelController#show should assign the requested travel as @travel
     Failure/Error: @user = FactoryGirl.create(:user)
     ActiveRecord::StatementInvalid:
       Mysql2::Error: Table 'travelphoto_test.users' doesn't exist: SHOW FULL FIELDS FROM `users`
     # ./spec/controllers/travel_controller_spec.rb:6:in `block (2 levels) in <top (required)>'

ログによるとtest環境にテーブルができていない模様。
以下のコマンドでtest環境にテーブルを作成します。

rake db:migrate RAILS_ENV=test

まだ通りません。

TravelController#index should show all data when user logged in
     Failure/Error: sign_in :user, @user
     NoMethodError:
       undefined method `sign_in' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_1:0x007f9cfaa6a010>
     # ./spec/controllers/travel_controller_spec.rb:22:in `block (3 levels) in <top (required)>'

どうもdeviseのhelperメソッドが読めていない様子。
以下のコードを spec/controllers/travel_controller_spec.rbに追記します。

require 'spec_helper'

describe TravelController do

  include Devise::TestHelpers #これを追記

(以下略)

しかし、まだ以下のようなログをはきます。

Failure/Error: travel = @user.travels.first
     NoMethodError:
       undefined method `travels' for #<User:0x007f9a67631d30>
(以下略)

UserからTravelsが取得できないっぽいので、UserのModelを確認したところ、「has_many :travels」がUser modelにありません。
以下のように修正しました。

//app/models/user.rb
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :confirmable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
  attr_accessible :username
  # attr_accessible :title, :body

  has_many :photos
  has_many :friends
  has_many :travels
  has_many :followings, :through => :friends
  validates_uniqueness_of :username
end

これでテストはなんとかクリア!

p.170からのPOSTを伴うテスト

まずはこんなエラーログをはきました。

/Users/****/travelphoto/spec/controllers/travel_controller_spec.rb:83: invalid multibyte char (US-ASCII) (SyntaxError)
/Users/****/travelphoto/spec/controllers/travel_controller_spec.rb:83: invalid multibyte char (US-ASCII)
/Users/****/travelphoto/spec/controllers/travel_controller_spec.rb:83: syntax error, unexpected $end, expecting '}'
    @travel_params = { :title => "タイトル",
                                    ^
(以下略)

これはソース内に「タイトル」という日本語を使用しているのが原因です。
travel_controller_spec.rbの先頭に「# coding: utf-8」を追記してください。

# coding: utf-8
require 'spec_helper'

describe TravelController do
(以下略)

p.176,177のテストが通らない

p.176のテストを実装した後にRSpecを実行すると、以下のようなログをはいてテストが通りません。

Failure/Error: @album = FactoryGirl.create(:album, :travel => @travel)
     ArgumentError:
       Factory not registered: album

FactoryGirlをうまく読み込めていないので、以下のコードを「/config/application.rbに追記します。

config.generators.fixture_replacement :factory_girl, dir: 'spec/factories'


でも、まだテストが通りません。

Failure/Error: @photo = FactoryGirl.create(:photo, :album => @album)
     Paperclip::Errors::MissingRequiredValidatorError:
       Paperclip::Errors::MissingRequiredValidatorError

ValidatorErrorとのことです。
ちょっと調べたらこのような記事がありました。
amazon s3 - heroku paperclip weird error Paperclip::Errors::MissingRequiredValidatorError - Stack Overflow

以下のコードを「models/photo.rb」のendの前に追記して解決しました。
(:content_typeは適当です)

validates_attachment_content_type :image, :content_type => %w(image/jpeg image/jpg image/png)

7-4「実装を自分でやってみましょう」というぶん投げ仕様

しかも、ダウンロードしてきたサンプルプログラムにも、「rails g」したままの状態のファイルが突っ込んであるというやっつけ仕事!
さすがにちょっとやる気がなくなりました。
もしも今度暇ができたら自分で実装するかもしれませんがあまりご期待ならさないでください・・・。

ちなみに、p.180のテストも、「spec」フォルダ以下に、「fixtures」というフォルダを作り、その中に「rails.png」を入れなければ通りません。

所感

さすがにやっつけ仕事すぎるなぁという箇所が増えてきました。
詳細 -- 栗田 由菜「RailsとiPhoneではじめるアプリケーション開発」Impress - みんなで正誤表 なしではもう進めません。
p.006にDRYの基本理念について言及してあるものの、同じようなソースがコピペで何度も出てきたり、誤字脱字、いくらバージョンによるトラブルが発生しやすいRailsとは言え、そのままではうまくいかない事が多数出てきたりと、どうも筆者の方はきれいなコードを書いたり、プログラムの本質をつかんだりというよりは、とりあえずの製品を作るスピードを重視する方のように感じました。