新米パパの育児留学

新米パパの育児留学

未経験からエンジニアへの転職体験談など "リアル" な情報を発信

IT/WEBエンジニアの転職(未経験/30代可あり)エージェント, サービス比較(p.s.侍の炎上を見て)
全くの未経験からIT/Webエンジニアに転職した私(30代)のロードマップ
30代未経験からIT / Webエンジニアへのリアルな転職体験談4 ”2度目の転職活動から入社へ”
本当に使えるものだけ!出産準備品・ベビー用品で実際に買ってよかったおすすめ10選
クロスバイク  LIG(リグ) MOVE 700Cの組み立て手順まとめ
Ruby初心者におすすめの学習方法「プロを目指す人のためのRuby入門」
Ruby on Rails チュートリアル 完全攻略 概要と演習解答総まとめ

【第7章】Ruby on Rails チュートリアル 5.0(第4版)演習と解答まとめ

Ruby on Rails Tutorial最新版の演習と解答です。

GEEKLYのIT・WEB・ソーシャルゲーム業界への転職支援サービス

目的

Ruby on Rails チュートリアル 5.0(第4版)を学習中です。

学習を進める中で演習問題の解答がなかった(*1,2)ので、自分なりにまとめていくこととしました。

アウトプットし、自分の理解を深めることを目的としています。 もし、記載内容に誤りがあった場合はコメントいただけると幸いです。

(*1)著者による有償版の解答はあるようです。正式な解答をご希望の方はこちらを参照ください。

Learn Web Development with Rails: Michael Hartl's Ruby on Rails Tutorial | Softcover.io

(*2)旧版に関する解答はありましたが、最新版 5.0(第4版)に関しては検索しても出てきませんでした。

演習問題と解答

演習7.1.1

演習7.1.1.1

<問題> ブラウザから /about にアクセスし、デバッグ情報が表示されていることを確認してください。このページを表示するとき、どのコントローラとアクションが使われていたでしょうか? paramsの内容から確認してみましょう。

<解答> 以下のデバッグ情報が表示されます。 "static_pages"コントローラーの"about"アクションが実行された。

--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: static_pages
  action: about
permitted: false

演習7.1.1.2

<問題> Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数userに格納してください。その後、puts user.attributes.to_yamlを実行すると何が表示されますか? ここで表示された結果と、yメソッドを使ったy user.attributesの実行結果を比較してみましょう。

<解答> 実行結果は以下の通り。 "puts user.attributes.to_yaml"の実行結果と"y user.attributes"の実行結果は同じです。

>> user=User.first
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Yamada", email: "mhartl@example.com", created_at: "2017-02-05 02:01:37", updated_at: "2017-02-05 02:36:54", password_digest: "$2a$10$E.gAC.d0Ch5dvmrM6vnNhu6gIpNtwFD8JhHmKPyc/V3...">

>> puts user.attributes.to_yaml
---
id: 1
name: Yamada
email: mhartl@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &1 2017-02-05 02:01:37.355601000 Z
  zone: &2 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &3 2017-02-05 02:36:54.834356000 Z
  zone: *2
  time: *3
password_digest: "$2a$10$E.gAC.d0Ch5dvmrM6vnNhu6gIpNtwFD8JhHmKPyc/V3u1di9B67dO"
=> nil

>> y user.attributes
---
id: 1
name: Yamada
email: mhartl@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &1 2017-02-05 02:01:37.355601000 Z
  zone: &2 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &3 2017-02-05 02:36:54.834356000 Z
  zone: *2
  time: *3
password_digest: "$2a$10$E.gAC.d0Ch5dvmrM6vnNhu6gIpNtwFD8JhHmKPyc/V3u1di9B67dO"
=> nil

演習7.1.2

演習7.1.2.1

<問題> 埋め込みRubyを使って、マジックカラム (created_atとupdated_at) の値をshowページに表示してみましょう (リスト 7.4)。

<解答>

<%= @user.name %>, <%= @user.email %>, <%= @user.created_at %>, <%= @user.updated_at %>

f:id:mochikichi321:20170219201416p:plain

演習7.1.2.2

<問題> 埋め込みRubyを使って、Time.nowの結果をshowページに表示してみましょう。ページを更新すると、その結果はどう変わっていますか? 確認してみてください。

<解答>

<%= @user.name %>, <%= @user.email %>, <%= @user.created_at %>, <%= @user.updated_at %>,
<%= Time.now %>

f:id:mochikichi321:20170219201506p:plain

更新すると表示時間も更新されます。

演習7.1.3

演習7.1.3.1

<問題> showアクションの中にdebuggerを差し込み (リスト 7.6)、ブラウザから /users/1 にアクセスしてみましょう。その後コンソールに移り、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。ヒント: 7.1.1.1の演習を参考にしてください。その演習ではdebugメソッドで表示したデバッグ情報を、どのようにしてYAML形式で表示していたでしょうか?

<解答>

(byebug) a=params
<ActionController::Parameters {"controller"=>"users", "action"=>"show", "id"=>"1"} permitted: false>

(byebug) puts a.to_yaml
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: users
  action: show
  id: '1'
permitted: false
nil

7.1.1.1の演習に関して、 debugヘルパーは、YAMLフォーマットを使ったオブジェクトを描画した\<pre>タグを返します。

演習7.1.3.2

<問題> newアクションの中にdebuggerを差し込み、/users/new にアクセスしてみましょう。@userの内容はどのようになっているでしょうか? 確認してみてください。

<解答>

(byebug) @user
nil

演習7.1.4

演習7.1.4.1

<問題> (任意) Gravatar上にアカウントを作成し、あなたのメールアドレスと適当な画像を紐付けてみてください。メールアドレスをMD5ハッシュ化して、紐付けた画像がちゃんと表示されるかどうか試してみましょう。

<解答> 省略

演習7.1.4.2

<問題> 7.1.4で定義したgravatar_forヘルパーをリスト 7.12のように変更して、sizeをオプション引数として受け取れるようにしてみましょう。うまく変更できると、gravatar_for user, size: 50といった呼び出し方ができるようになります。重要: この改善したヘルパーは10.3.1で実際に使います。忘れずに実装しておきましょう。

<解答> リスト7.12参照。

演習7.1.4.3

<問題> オプション引数は今でもRubyコミュニティで一般的に使われていますが、Ruby 2.0から導入された新機能「キーワード引数 (Keyword Arguments)」でも実現することができます。先ほど変更したリスト 7.12を、リスト 7.13のように置き換えてもうまく動くことを確認してみましょう。この2つの実装方法はどういった違いがあるのでしょうか? 考えてみてください。

<解答> 動作確認のみなので省略。 オプション引数よりもキーワード引数の方が簡潔に実装できる。

演習7.2.1

演習7.2.1.1

<問題> 試しに、リスト 7.15にある:nameを:nomeに置き換えてみましょう。どんなエラーメッセージが表示されるようになりますか?

<解答> undefined method `nome'

演習7.2.1.2

<問題> 試しに、ブロックの変数fをすべてfoobarに置き換えてみて、結果が変わらないことを確認してみてください。確かに結果は変わりませんが、変数名をfoobarとするのはあまり良い変更ではなさそうですね。その理由について考えてみてください。

<解答> 変数fは “form” のfを使用している。 "f.label"等がHTMLフォーム要素に対応することがわかるようにする。 "foobar"はメタ構文変数(意味を持たない名前)として認識されるため適さない。

演習7.2.2

演習7.2.2.1

<問題> Learn Enough HTML to Be DangerousではHTMLをすべて手動で書き起こしていますが、なぜformタグを使わなかったのでしょうか? 理由を考えてみてください。

<解答> formタグは、入力・送信フォームを作成するために使用される。 本文中では、入力・送信が必要ないので使用していない。 (ログインページにはformタグが使用されています。)

演習7.3.2

演習7.3.2.1

<問題> /users/new?admin=1 にアクセスし、paramsの中にadmin属性が含まれていることをデバッグ情報から確認してみましょう。

<解答>

--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  admin: '1'
  controller: users
  action: new
permitted: false

演習7.3.3

演習7.3.3.1

<問題> 最小文字数を5に変更すると、エラーメッセージも自動的に更新されることを確かめてみましょう。

<解答>

[user.rb]


class User < ApplicationRecord
(中略)
  validates :password, presence: true, length: { minimum: 5 }  
end

f:id:mochikichi321:20170219201509p:plain

演習7.3.3.2

<問題> 未送信のユーザー登録フォーム (図 7.12) のURLと、送信済みのユーザー登録フォーム (図 7.18) のURLを比べてみましょう。なぜURLは違っているのでしょうか? 考えてみてください。

<解答> 未送信のユーザー登録フォーム (図 7.12) のURLは以下。 "・・・/signup"

ルーティングの以下が実行されている。

[routes.rb]

(前略)
  get '/signup',    to: 'users#new'
(後略)

送信済みのユーザー登録フォーム (図 7.18) のURLは以下。 "・・・/users"

ルーティングの以下が実行されている。

[routes.rb]

(前略)
  resources :users
(後略)

これは、表7.1のルートを指し、その中の"ユーザーを作成するアクション"が実行されている。

  post '/users'  'users#create'

演習7.3.4

演習7.3.4.1

<問題> リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。

<解答>

[users_signup_test.rb]

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path

(中略)

    assert_template 'users/new'
    assert_select 'div#error_explanation'
    assert_select 'div.alert'   
  end
end

演習7.3.4.2

<問題> 未送信のユーザー登録フォームと送信直後のURLは、それぞれ /signup と /users になり、URLが異なっています。これは、リスト 5.43で追加した名前付きルートと、デフォルトのRESTfulなルーティング (リスト 7.3) を設定したことによって生じた差異です。リスト 7.26とリスト 7.27の内容を追加し、この問題を解決してみてください。うまくいけば、いずれのURLも /signup となるはずです。あれ、でもテストは greenのままになっていますね...、なぜでしょうか? (考えてみてください)

<解答> リスト7.26とリスト7.27の内容を追加すると、いずれのURLも /signup となる。 GREENのままとなっている理由は演習7.3.4.3及び演習7.3.4.4参照。

演習7.3.4.3

<問題> リスト 7.25のpost部分を変更して、上の演習課題で作られた新しいURLに合わせてみましょう。また、テストが依然として greenのままになっている点も確認してください。

<解答>

[users_signup_test.rb]

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post signup_path, params: { user: { name:  "",
(後略)

テストはGREEN。

演習7.3.4.4

<問題> リスト 7.27のフォームを以前の状態 (リスト 7.20) に戻してみて、テストがやはり greenになっていることを確認してください。これは問題です! なぜなら、現在postが送信されているURLは正しくないのですから。assert_selectを使ったテストをリスト 7.25に追加し、このバグを検知できるようにしてみましょう (テストを追加して redになれば成功です)。その後、変更後のフォーム (リスト 7.27) に戻してみて、テストが green になることを確認してみましょう。ヒント: フォームから送信してテストするのではなく、’form[action="/signup"]’という部分が存在するかどうかに着目してテストしてみましょう。

<解答> リスト 7.27のフォームを以前の状態 (リスト 7.20) に戻してもテストはGREEN。

テストを以下の通りとするとテストはRED。

[users_signup_test.rb]

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do

(中略)

    assert_select 'form[action="/signup"]'
  end
end

リスト7.27に戻してテストするとGREEN。

演習7.4.1

演習7.4.1.1

<問題> 有効な情報を送信し、ユーザーが実際に作成されたことを、Railsコンソールを使って確認してみましょう。

<解答> 以下のユーザー情報を送信。

f:id:mochikichi321:20170219201516p:plain

二人目のユーザー情報が作成されました。(表示のさせ方はいろいろあります。)

>> User.second
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Yamada", email: "yamada@mail.com", created_at: "2017-02-09 06:56:06", updated_at: "2017-02-09 06:56:06", password_digest: "$2a$10$0JljS52iRoEmJQ5uhNbnVeDc9/cAuYWtKrMmour10cG...">

演習7.4.1.2

<問題> リスト 7.28を更新し、redirect_to user_url(@user)とredirect_to @userが同じ結果になることを確認してみましょう。

<解答> 動作確認のみなので省略。

演習7.4.2

演習7.4.2.1

<問題> コンソールに移り、文字列内の式展開 (4.2.2) でシンボルを呼び出してみましょう。例えば"#{:success}"といったコードを実行すると、どんな値が返ってきますか? 確認してみてください。

<解答>

>> "#{:success}"
=> "success"

演習7.4.2.2

<問題> 先ほどの演習で試した結果を参考に、リスト 7.30のflashはどのような結果になるか考えてみてください。

<解答>

>> flash = { success: "It worked!", danger: "It failed." }
=> {:success=>"It worked!", :danger=>"It failed."}

>> "#{flash[:success]}"
=> "It worked!"

>> "#{flash[:danger]}"
=> "It failed."

演習7.4.3

演習7.4.3.1

<問題> Railsコンソールを使って、新しいユーザーが本当に作成されたのかもう一度チェックしてみましょう。結果は、リスト 7.32のようになるはずです。

<解答> 動作確認のみなので省略。

演習7.4.3.2

<問題> 自分のメールアドレスでユーザー登録を試してみましょう。既にGravatarに登録している場合、適切な画像が表示されているか確認してみてください。

<解答> 動作確認のみなので省略。

演習7.4.4

演習7.4.4.1

<問題> 7.4.2で実装したflashに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.34に最小限のテンプレートを用意しておいたので、参考にしてください (FILL_INの部分を適切なコードに置き換えると完成します)。ちなみに、テキストに対するテストは壊れやすいです。文量の少ないflashのキーであっても、それは同じです。筆者の場合、flashが空でないかをテストするだけの場合が多いです。

<解答>

[users_signup_test.rb]

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

(中略)
  
  test "valid signup information" do
(中略)
    assert_not flash.empty?    
  end  
end

演習7.4.4.2

<問題> 本文中でも指摘しましたが、flash用のHTML (リスト 7.31) は読みにくいです。より読みやすくしたリスト 7.35のコードに変更してみましょう。変更が終わったらテストスイートを実行し、正常に動作することを確認してください。なお、このコードでは、Railsのcontent_tagというヘルパーを使っています。

<解答> 動作確認のみなので省略。

演習7.4.4.3

<問題> リスト 7.28のリダイレクトの行をコメントアウトすると、テストが失敗することを確認してみましょう。

<解答> 動作確認のみなので省略。

演習7.4.4.4

<問題> リスト 7.28で、@user.saveの部分をfalseに置き換えたとしましょう (バグを埋め込んでしまったと仮定してください)。このとき、assert_differenceのテストではどのようにしてこのバグを検知するでしょうか? テストコードを追って考えてみてください。

<解答> 以下のテストでは、assert_differenceブロック内の処理を実行する直前と、実行した直後のUser.countの値を比較し、1増えた際にtrueとなる。@user.saveが実行されないことによって、User.countは増えないためerrorとなる。

assert_difference 'User.count', 1 do
  post users_path, ...
end

演習7.5.3

演習7.5.3.1

<問題> ブラウザから本番環境 (Heroku) にアクセスし、SSLの鍵マークがかかっているか、URLがhttpsになっているかどうかを確認してみましょう。

<解答> 動作確認のみなので省略。

演習7.5.3.1

<問題> 本番環境でユーザーを作成してみましょう。Gravatarの画像は正しく表示されているでしょうか?

<解答> 動作確認のみなので省略。

GEEKLYのIT・WEB・ソーシャルゲーム業界への転職支援サービス

あわせて読みたい記事

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com

おすすめの本

この本は、初心者にもわかりやすいとエンジニア界隈ではかなり著名な"伊藤 淳一"さんの本です。 私もいつもQiitaやブログでお世話になっており、わかりやすい解説に信頼を寄せていたので購入しました。

期待通り、いや、期待以上にわかりやすく丁寧な解説でしたのでかなり理解が深まったと思います。 私は参考書を読むのは退屈で頭に入ってこないタイプなのですが、わかりやすい解説に加えて実際に手を動かして理解を深められる例題が用意されているので楽しくサクサク進めていけます。

Rubyの基礎はProgateやドットインストールなどで理解した上で読まれると更に理解が深まると思います。 RailsスキルをレベルアップしていくためにもRubyの理解を深めることは非常に効果的です。 Railsチュートリアルを完了した方や、進めている途中の方で"Rubyのステップアップとしての次の一冊"をお探しの方におすすめです。