Ruby on Railsチュートリアルの演習問題と解答をまとめる。
第13章 ユーザーのマイクロポスト - Railsチュートリアル
アウトプットすることで、より自分の理解を深めることを目的としています。 自分なりに調べて考えた回答のため、記載内容に誤りがある場合はコメントいただけると幸いです。
- 演習13.1.1 基本的なモデル
- 演習13.1.2 Micropostのバリデーション
- 演習13.1.3 User/Micropostの関連付け
- 演習13.1.4 マイクロポストを改良する
- 13.2.1 マイクロポストの描画
- 演習13.2.2 マイクロポストのサンプル
- 演習13.2.3 プロフィール画面のマイクロポストをテストする
- 演習13.3.1 マイクロポストのアクセス制御
- 13.3.2 マイクロポストを作成する
- 演習13.3.3 フィードの原則
- 演習13.3.4 マイクロポストを削除する
- 演習13.3.5 フィード画面のマイクロポストをテストする
- 演習13.4.1 基本的な画像アップロード
- 演習13.4.2 画像の検証
- 演習13.4.3 画像のリサイズ
演習13.1.1 基本的なモデル
問題1
RailsコンソールでMicropost.newを実行し、インスタンスを変数micropostに代入してください。その後、user_idに最初のユーザーのidを、contentに "Lorem ipsum" をそれぞれ代入してみてください。この時点では、 micropostオブジェクトのマジックカラム (created_atとupdated_at) には何が入っているでしょうか?
解答
>> micropost = Micropost.new => #<Micropost id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil> >> user = User.first (省略) >> micropost.user_id = user.id => 1 >> micropost.content = "Lorem ipsum" => "Lorem ipsum" >> micropost.created_at => nil >> micropost.updated_at => nil
問題2
先ほど作ったオブジェクトを使って、micropost.userを実行してみましょう。どのような結果が返ってくるでしょうか? また、micropost.user.nameを実行した場合の結果はどうなるでしょうか?
解答
>> micropost.user User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] => #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2019-11-02 11:10:05", updated_at: "2019-11-02 12:32:19", password_digest: "$2a$10$ZzyZENoEMcOQx6UOj325Yez2q6GcU9WsBAaqexlZByD...", remember_digest: nil, admin: true, activation_digest: "$2a$10$HveqjOfpJGKOF0sgQEDSSuu6q1oVkdv4njV0CTqQ/tY...", activated: true, activated_at: "2019-11-02 11:10:05", reset_digest: "$2a$10$fqmrs.nZER5KznyyjYht4uI3otro3Zqxklj6EMlegSW...", reset_sent_at: "2019-11-02 11:27:52"> >> micropost.user.name => "Example User"
問題3
先ほど作ったmicropostオブジェクトをデータベースに保存してみましょう。この時点でもう一度マジックカラムの内容を調べてみましょう。今度はどのような値が入っているでしょうか?
解答
>> micropost.save (0.2ms) begin transaction SQL (2.9ms) INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2019-11-02 17:44:46.408659"], ["updated_at", "2019-11-02 17:44:46.408659"]] (1.0ms) commit transaction => true >> micropost.created_at => Sat, 02 Nov 2019 17:44:46 UTC +00:00 >> micropost.updated_at => Sat, 02 Nov 2019 17:44:46 UTC +00:00
演習13.1.2 Micropostのバリデーション
問題1
Railsコンソールを開き、user_idとcontentが空になっているmicropostオブジェクトを作ってみてください。このオブジェクトに対してvalid?を実行すると、失敗することを確認してみましょう。また、生成されたエラーメッセージにはどんな内容が書かれているでしょうか?
解答
>> micropost = Micropost.new => #<Micropost id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil> >> micropost.valid? => false >> micropost.errors.full_messages => ["User must exist", "User can't be blank", "Content can't be blank"]
問題2
コンソールを開き、今度はuser_idが空でcontentが141文字以上のmicropostオブジェクトを作ってみてください。このオブジェクトに対してvalid?を実行すると、失敗することを確認してみましょう。また、生成されたエラーメッセージにはどんな内容が書かれているでしょうか?
解答
>> micropost = Micropost.new(content: "a" * 141) => #<Micropost id: nil, content: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", user_id: nil, crea ted_at: nil, updated_at: nil> >> micropost.valid? => false >> micropost.errors.full_messages => ["User must exist", "User can't be blank", "Content is too long (maximum is 140 characters)"]
演習13.1.3 User/Micropostの関連付け
問題1
データベースにいる最初のユーザーを変数userに代入してください。そのuserオブジェクトを使ってmicropost = user.microposts.create(content: "Lorem ipsum")を実行すると、どのような結果が得られるでしょうか?
解答
>> user = User.first (省略) >> micropost = user.microposts.create(content: "Lorem ipsum") (0.1ms) begin transaction SQL (0.7ms) INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2019-11-02 18:10:30.355788"], ["updated_at", "2019-11-02 18:10:30.355788"]] (1.6ms) commit transaction => #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-11-02 18:10:30", updated_at: "2019-11-02 18:10:30">
問題2
先ほどの演習課題で、データベース上に新しいマイクロポストが追加されたはずです。user.microposts.find(micropost.id)を実行して、本当に追加されたのかを確かめてみましょう。また、先ほど実行したmicropost.idの部分をmicropostに変更すると、結果はどうなるでしょうか?
解答
>> user.microposts.find(micropost.id) Micropost Load (0.3ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ? [["user_id", 1], ["id", 2], ["LIMIT", 1]] => #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-11-02 18:10:30", updated_at: "2019-11-02 18:10:30"> >> user.microposts.find(micropost) Traceback (most recent call last): 1: from (irb):4 ArgumentError (You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`.)
問題3
user == micropost.userを実行した結果はどうなるでしょうか? また、user.microposts.first == micropost を実行した結果はどうなるでしょうか? それぞれ確認してみてください。
解答
>> user == micropost.user => true >> user.microposts.first == micropost Micropost Load (0.3ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ? [["user_id", 1], ["LIMIT", 1]] => false
演習13.1.4 マイクロポストを改良する
問題1
Micropost.first.created_atの実行結果と、Micropost.last.created_atの実行結果を比べてみましょう。
解答
>> Micropost.first.created_at Micropost Load (1.8ms) SELECT "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC L IMIT ? [["LIMIT", 1]] => Sat, 02 Nov 2019 18:10:30 UTC +00:00 >> Micropost.last.created_at Micropost Load (0.5ms) SELECT "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LI MIT ? [["LIMIT", 1]] => Sat, 02 Nov 2019 17:44:46 UTC +00:00
問題2
Micropost.firstを実行したときに発行されるSQL文はどうなっているでしょうか? 同様にして、Micropost.lastの場合はどうなっているでしょうか? ヒント: それぞれをコンソール上で実行したときに表示される文字列が、SQL文になります。
解答
Micropost Load (0.3ms) SELECT "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC L IMIT ? [["LIMIT", 1]] => #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-11-02 18:10:30", updated_at: "20 19-11-02 18:10:30"> >> Micropost.last Micropost Load (0.2ms) SELECT "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LI MIT ? [["LIMIT", 1]] => #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2019-11-02 17:44:46", updated_at: "2019-11-02 17:44:46">
問題3
データベース上の最初のユーザーを変数userに代入してください。そのuserオブジェクトが最初に投稿したマイクロポストのidはいくつでしょうか? 次に、destroyメソッドを使ってそのuserオブジェクトを削除してみてください。削除すると、そのuserに紐付いていたマイクロポストも削除されていることをMicropost.findで確認してみましょう。
解答
>> user = User.first (省略) >> user.microposts.first Micropost Load (0.2ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? [["user_id", 1], ["LIMIT", 1]] => #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-11-02 18:10:30", updated_at: "2019-11-02 18:10:30"> >> user.destroy (0.1ms) begin transaction Micropost Load (0.4ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC [["user_id", 1]] SQL (0.7ms) DELETE FROM "microposts" WHERE "microposts"."id" = ? [["id", 2]] SQL (0.1ms) DELETE FROM "microposts" WHERE "microposts"."id" = ? [["id", 1]] SQL (0.2ms) DELETE FROM "users" WHERE "users"."id" = ? [["id", 1]] (1.5ms) commit transaction => #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2019-11-02 11:10:05", updated_at: "2019-11-02 12:32:19", password_digest: "$2a$10$ZzyZENoEMcOQx6UOj325Yez2q6GcU9WsBAaqexlZByD...", remember_digest: nil, admin: true, activation_digest: "$2a$10$HveqjOfpJGKOF0sgQEDSSuu6q1oVkdv4njV0CTqQ/tY...", activated: true, activated_at: "2019-11-02 11:10:05", reset_digest: "$2a$10$fqmrs.nZER5KznyyjYht4uI3otro3Zqxklj6EMlegSW...", reset_sent_at: "2019-11-02 11:27:52"> >> Micropost.find Traceback (most recent call last): 1: from (irb):9 ActiveRecord::RecordNotFound (Couldn't find Micropost without an ID) >> Micropost.find(1) Micropost Load (0.3ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? [["id", 1], ["LIMIT", 1]] Traceback (most recent call last): 1: from (irb):10 ActiveRecord::RecordNotFound (Couldn't find Micropost with 'id'=1)
13.2.1 マイクロポストの描画
問題1
7.3.3で軽く説明したように、今回ヘルパーメソッドとして使ったtime_ago_in_wordsメソッドは、Railsコンソールのhelperオブジェクトから呼び出すことができます。このhelperオブジェクトのtime_ago_in_wordsメソッドを使って、3.weeks.agoや6.months.agoを実行してみましょう。
解答
>> helper.time_ago_in_words(3.weeks.ago) => "21 days" >> helper.time_ago_in_words(6.month.ago) => "6 months"
問題2
helper.time_ago_in_words(1.year.ago)と実行すると、どういった結果が返ってくるでしょうか?
解答
>> helper.time_ago_in_words(1.year.ago) => "about 1 year"
問題3
micropostsオブジェクトのクラスは何でしょうか? ヒント: リスト 13.23内のコードにあるように、まずはpaginateメソッド (引数はpage: nil) でオブジェクトを取得し、その後classメソッドを呼び出してみましょう。
解答
>> user = User.find(1) (中略) >> microposts = user.microposts.paginate(page: nil) Micropost Load (0.7ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ? [["user_id", 1], ["LIMIT", 11], ["OFFSET", 0]] => #<ActiveRecord::AssociationRelation []> >> microposts.class => Micropost::ActiveRecord_AssociationRelation
演習13.2.2 マイクロポストのサンプル
問題1
(1..10).to_a.take(6)というコードの実行結果を推測できますか? 推測した値が合っているかどうか、実際にコンソールを使って確認してみましょう。
解答
>> (1..10).to_a.take(6) => [1, 2, 3, 4, 5, 6]
問題2
先ほどの演習にあったto_aメソッドの部分は本当に必要でしょうか? 確かめてみてください。
解答
>> (1..10).take(6) => [1, 2, 3, 4, 5, 6]
必要ない
問題3
Fakerはlorem ipsum以外にも、非常に多種多様の事例に対応しています。Fakerのドキュメント (英語) を眺めながら画面に出力する方法を学び、実際に大学名や電話番号、Hipster IpsumやChuck Norris facts (参考: チャック・ノリスの真実) を画面に出力してみましょう。(訳注: もちろん日本語にも対応していて、例えば沖縄らしい用語を出力するfaker-okinawaもあります。ぜひ遊んでみてください。)
解答
>> Faker::University.name => "East New Jersey College" >> Faker::PhoneNumber.phone_number => "1-415-667-6314 x53799" >> Faker::Hipster.words => ["cardigan", "taxidermy", "squid"] >> Faker::ChuckNorris.fact => "Chuck Norris can compile syntax errors." >> Faker::Ancient.god => "Dionysus"
演習13.2.3 プロフィール画面のマイクロポストをテストする
問題1
リスト 13.28にある2つの'h1'のテストが正しいか確かめるため、該当するアプリケーション側のコードをコメントアウトしてみましょう。テストが green から redに変わることを確認してみてください。
解答
[app/views/users/show.html.erb] <% provide(:title, @user.name) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <h1> <% #= gravatar_for @user %> <%= @user.name %> </h1> </section> </aside> (中略) </div>
テストがredになる
問題2
リスト 13.28にあるテストを変更して、will_paginateが1度のみ表示されていることをテストしてみましょう。ヒント: 表 5.2を参考にしてください。
解答
[test/integration/users_profile_test.rb] require 'test_helper' class UsersProfileTest < ActionDispatch::IntegrationTest include ApplicationHelper def setup @user = users(:michael) end test "profile display" do get user_path(@user) assert_template 'users/show' assert_select 'title', full_title(@user.name) assert_select 'h1', text: @user.name assert_select 'h1>img.gravatar' assert_match @user.microposts.count.to_s, response.body assert_select 'div.pagination', count: 1 # 追加 @user.microposts.paginate(page: 1).each do |micropost| assert_match micropost.content, response.body end end end
演習13.3.1 マイクロポストのアクセス制御
問題1
なぜUsersコントローラ内にあるlogged_in_userフィルターを残したままにするとマズイのでしょうか? 考えてみてください。
解答
railsのDRY(Don't repeat yourself)に反するため。
無駄なコードが増えて、エラーの原因になる
13.3.2 マイクロポストを作成する
問題1
Homeページをリファクタリングして、if-else文の分岐のそれぞれに対してパーシャルを作ってみましょう。
解答
[app/views/static_pages/home.html.erb] <% if logged_in? %> <%= render 'static_pages/home_logged_in' %> <% else %> <%= render 'static_pages/home_not_logged_in' %> <% end %>
[app/views/static_pages/_home_lodgged_in.html.erb] <div class="row"> <aside class="col-md-4"> <section class="user_info"> <%= render 'shared/user_info' %> </section> <section class="micropost_form"> <%= render 'shared/micropost_form' %> </section> </aside> </div>
[app/views/static_pages/_home_not_logged_in.html.erb] <div class="center jumbotron"> <h1>Welcom to the Sample App</h1> <h2> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </h2> <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %> </div> <%= link_to image_tag("rails.png", alt: "Rails logo"), 'http://rubyonrails.org/' %>
演習13.3.3 フィードの原則
問題1
新しく実装したマイクロポストの投稿フォームを使って、実際にマイクロポストを投稿してみましょう。Railsサーバーのログ内にあるINSERT文では、どういった内容をデータベースに送っているでしょうか? 確認してみてください。
解答
(0.1ms) begin transaction SQL (2.9ms) INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "カラダにピース"], ["user_id", 1], ["created_at", "2019-11-03 09:26:02.622273"], ["updated_at", "2019-11-03 09:26:02.622273"]] (1.5ms) commit transaction
問題2
コンソールを開き、user変数にデータベース上の最初のユーザーを代入してみましょう。その後、Micropost.where("user_id = ?", user.id)とuser.microposts、そしてuser.feedをそれぞれ実行してみて、実行結果がすべて同じであることを確認してみてください。ヒント: ==で比較すると結果が同じかどうか簡単に判別できます。
解答
>> user = User.first (省略 >> Micropost.where("user_id = ?", user.id) == user.microposts Micropost Load (1.5ms) SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC [["user_id", 1]] Micropost Load (0.4ms) SELECT "microposts".* FROM "microposts" WHERE (user_id = 1) ORDER BY "microposts"."created_at" DESC => true >> user.microposts == user.feed Micropost Load (0.5ms) SELECT "microposts".* FROM "microposts" WHERE (user_id = 1) ORDER BY "microposts"."created_at" DESC => true
演習13.3.4 マイクロポストを削除する
問題1
マイクロポストを作成し、その後、作成したマイクロポストを削除してみましょう。次に、Railsサーバーのログを見てみて、DELETE文の内容を確認してみてください。
解答
(0.1ms) begin transaction SQL (0.8ms) DELETE FROM "microposts" WHERE "microposts"."id" = ? [["id", 302]] (1.2ms) commit transaction
問題2
redirect_to request.referrer || root_urlの行をredirect_back(fallback_location: root_url)と置き換えてもうまく動くことを、ブラウザを使って確認してみましょう (このメソッドはRails 5から新たに導入されました)。
解答
def destroy @micropost.destroy flash[:success] = "Micropost deleted" # redirect_to request.referrer || root_url redirect_back(fallback_location: root_url) end
動作確認ok
演習13.3.5 フィード画面のマイクロポストをテストする
問題1
リスト 13.55で示した4つのコメント (「無効な送信」など) のそれぞれに対して、テストが正しく動いているか確認してみましょう。具体的には、対応するアプリケーション側のコードをコメントアウトし、テストが redになることを確認し、元に戻すと greenになることを確認してみましょう。
解答
「無効な送信」
contentのvalidatesをコメントアウトするとエラーになる
[app/models/micropost.rb] class Micropost < ApplicationRecord belongs_to :user default_scope -> { order(created_at: :desc) } validates :user_id, presence: true # validates :content, presence: true, length: { maximum: 140 } end
「有効な送信」
有効な送信を受けた後の処理をコメントアウトするとエラーになる
[app/controllers/microposts_controller.rb] def create @micropost = current_user.microposts.build(micropost_params) if @micropost.save # flash[:success] = "Micropost created!" # redirect_to root_url else @feed_items = [] render 'static_pages/home' end end
「投稿を削除する」
deleteのリンクをコメントアウトするとエラーになる
[app/views/micropost.html.erb] <li id="micropost-<%= micropost.id %>"> <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %> <span class="user"><%= link_to micropost.user.name, micropost.user %></span> <span class="content"><%= micropost.content %></span> <span class="timestamp"> Posted <%= time_ago_in_words(micropost.created_at) %> agp. <% if current_user?(micropost.user) %> <% #= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %> <% end %> </span> </li>
「違うユーザーのプロフィールにアクセス(削除リンクがないことを確認)」
if current_user?をコメントアウトするとエラーになる
[app/views/micropost.html.erb] <li id="micropost-<%= micropost.id %>"> <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %> <span class="user"><%= link_to micropost.user.name, micropost.user %></span> <span class="content"><%= micropost.content %></span> <span class="timestamp"> Posted <%= time_ago_in_words(micropost.created_at) %> agp. <% # if current_user?(micropost.user) %> <%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %> <% # end %> </span> </li>
問題2
サイドバーにあるマイクロポストの合計投稿数をテストしてみましょう。このとき、単数形 (micropost) と複数形 (microposts) が正しく表示されているかどうかもテストしてください。ヒント: リスト 13.57を参考にしてみてください。
解答
[test/integration/microposts_interface_test.rb] test "micropost sidebar count" do log_in_as(@user) get root_path assert_match "#{@user.microposts.count} microposts", response.body # まだマイクロポストを投稿していないユーザー other_user = users(:malory) log_in_as(other_user) get root_path assert_match "0 microposts", response.body other_user.microposts.create!(content: "A micropost") get root_path assert_match "1 micropost", response.body end
演習13.4.1 基本的な画像アップロード
問題1
画像付きのマイクロポストを投稿してみましょう。もしかして、大きすぎる画像が表示されてしまいましたか? (心配しないでください、次の13.4.3でこの問題を直します)。
解答
問題2
リスト 13.63に示すテンプレートを参考に、13.4で実装した画像アップローダーをテストしてください。テストの準備として、まずはサンプル画像をfixtureディレクトリに追加してください (コマンド例: cp app/assets/images/rails.png test/fixtures/)。リスト 13.63で追加したテストでは、Homeページにあるファイルアップロードと、投稿に成功した時に画像が表示されているかどうかをチェックしています。なお、テスト内にあるfixture_file_uploadというメソッドは、fixtureで定義されたファイルをアップロードする特別なメソッドです18。ヒント: picture属性が有効かどうかを確かめるときは、11.3.3で紹介したassignsメソッドを使ってください。このメソッドを使うと、投稿に成功した後にcreateアクション内のマイクロポストにアクセスするようになります。
解答
サンプル画像をfixtureディレクトリに追加する
cp app/assets/images/rails.png test/fixtures/
リスト13.63を参考にテストを追加する
require 'test_helper' class MicropostsInterfaceTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end test "micropost interface" do log_in_as(@user) get root_path assert_select 'div.pagination' assert_select 'input[type=file]' # 無効な送信 assert_no_difference 'Micropost.count' do post microposts_path, params: { micropost: { content: "" } } end assert_select 'div#error_explanation' # 有効な送信 content = "This micropost really ties the room together" picture = fixture_file_upload('test/fixtures/rails.png', 'image/png') assert_difference 'Micropost.count', 1 do post microposts_path, params: { micropost: { content: content, picture: picture } } end assert_redirected_to root_url follow_redirect! assert_match content, response.body # 投稿を削除する assert_select 'a', text: 'delete' first_micropost = @user.microposts.paginate(page: 1).first assert_difference 'Micropost.count', -1 do delete micropost_path(first_micropost) end # 違うユーザーのプロフィールにアクセス(削除リンクがないことを確認) get user_path(users(:archer)) assert_select 'a', text: 'delete', count: 0 end 略 end
演習13.4.2 画像の検証
問題1
5MB以上の画像ファイルを送信しようとした場合、どうなりますか?
解答
警告が表示される
問題2
無効な拡張子のファイルを送信しようとした場合、どうなりますか?
解答
エラーメッセージが表示される
演習13.4.3 画像のリサイズ
問題1
解像度の高い画像をアップロードし、リサイズされているかどうか確認してみましょう。画像が長方形だった場合、リサイズはうまく行われているでしょうか?
解答
いい感じのサイズになりました。
問題2
既にリスト 13.63のテストを追加していた場合、この時点でテストスイートを走らせるとエラーメッセージが表示されるようになるはずです。このエラーを取り除いてみましょう。ヒント: リスト 13.68にある設定ファイルを修正し、テスト時はCarrierWaveに画像のリサイズをさせないようにしてみましょう。
解答
13.63のテストを追加しているが、エラーなし
お疲れ様でした。