読者です 読者をやめる 読者になる 読者になる

新米パパの育児留学

子供との幸せな時間を今だけではなく、一生大切にしたいという思いから、育休中にプログラミングを学習しエンジニアを目指します。

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

プログラミング プログラミング-Rails_チュートリアル

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

f:id:mochikichi321:20170206212242p:plain

目的

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版)に関しては検索しても出てきませんでした。

プログラミングを学習し始めたきっかけについてはこちら

mochikichi.hatenablog.com

演習問題と解答

演習4.2.2

演習4.2.2.1

<問題> city変数に適当な市区町村を、prefecture変数に適当な都道府県を代入してください。

<解答>

>>city="神戸"
=> "神戸"
>>prefecture="兵庫"
=> "兵庫"

演習4.2.2.2

<問題> 先ほど作った変数と式展開を使って、「東京都 新宿区」のような住所の文字列を作ってみましょう。出力にはputsを使ってください。

<解答>

>>puts "#{prefecture}県 #{city}市"
=> 兵庫県 神戸市

演習4.2.2.3

<問題> 上記の文字列の間にある半角スペースをタブに置き換えてみてください。(ヒント: 改行文字と同じで、タブも特殊文字です)

<解答>

>>puts "#{prefecture}県 \t #{city}市"
=> 兵庫県    神戸市

演習4.2.2.4

<問題> タブに置き換えた文字列を、ダブルクォートからシングルクォートに置き換えてみるとどうなるでしょうか?

<解答>

>>puts '#{prefecture}県 \t #{city}市'
=> #{prefecture}県 \t #{city}市

演習4.2.3

演習4.2.3.1

<問題> “racecar” の文字列の長さはいくつですか? lengthメソッドを使って調べてみてください。

<解答>

>> "racecar".length
=> 7

演習4.2.3.2

<問題> reverseメソッドを使って、"racecar"の文字列を逆から読むとどうなるか調べてみてください。

<解答>

>>"racecar".reverse
=> "racecar"

演習4.2.3.3

<問題> 変数sに “racecar” を代入してください。その後、比較演算子 (==) を使って変数sとs.reverseの値が同じであるかどうか、調べてみてください。

<解答>

>>s="racecar"
=> "racecar"
>>s==s.reverse
=> true

演習4.2.3.4

<問題> リスト 4.9を実行すると、どんな結果になるでしょうか? 変数sに “onomatopoeia” という文字列を代入するとどうなるでしょうか? ヒント: 上矢印 (またはCtrl-Pコマンド) を使って以前に使ったコマンドを再利用すると一からコマンドを全部打ち込む必要がなくて便利ですよ。)

<解答>

>>puts "It's a palindrome!" if s == s.reverse
=>It's a palindrome!

>>s="onomatopoeia"
=> "onomatopoeia"

>>puts "It's a palindrome!" if s == s.reverse
=> nil

演習4.2.4

演習4.2.4.1

<問題> リスト 4.10のFILL_INの部分を適切なコードに置き換え、回文かどうかをチェックするメソッドを定義してみてください。ヒント: リスト 4.9の比較方法を参考にしてください。

<解答>

>>def palindrome_tester(s)
>> if s==s.reverse
>>  puts "It's a palindrome!"
>> else
>>  puts "It's not a palindrome."
>> end
>>end
=> :palindrome_tester

演習4.2.4.2

<問題> 上で定義したメソッドを使って “racecar” と “onomatopoeia” が回文かどうかを確かめてみてください。1つ目は回文である、2つ目は回文でない、という結果になれば成功です。

<解答>

>>palindrome_tester("racecar")
=>It's a palindrome!
=> nil

>>palindrome_tester("onomatopoeia")
=>It's not a palindrome.
=> nil

演習4.2.4.3

<問題> palindrome_tester(“racecar”)に対してnil?メソッドを呼び出し、戻り値がnilであるかどうかを確認してみてください (つまりnil?を呼び出した結果がtrueであることを確認してください)。このメソッドチェーンは、nil?メソッドがリスト 4.10の戻り値を受け取り、その結果を返しているという意味になります。

<解答>

>>palindrome_tester("racecar").nil?
=>It's a palindrome!
=> true

演習4.3.1

演習4.3.1.1

<問題> 文字列 “A man, a plan, a canal, Panama” を “, ” で分割して配列にし、変数aに代入してみてください。

<解答>

>>a= "A man, a plan, a canal, Panama".split(', ')
=> ["A man", "a plan", "a canal", "Panama"]

演習4.3.1.2

<問題> 今度は、変数aの要素を連結した結果 (文字列) を、変数sに代入してみてください。

<解答>

>>s=a.join
=> "A mana plana canalPanama"

演習4.3.1.3

<問題> 変数sを半角スペースで分割した後、もう一度連結して文字列にしてください (ヒント: メソッドチェーンを使うと1行でもできます)。リスト 4.10で使った回文をチェックするメソッドを使って、(現状ではまだ) 変数sが回文ではないことを確認してください。downcaseメソッドを使って、s.downcaseは回文であることを確認してください。

<解答>

>>def palindrome_tester(s)
>> if s==s.reverse
>>  puts "It's a palindrome!"
>> else
>>  puts "It's not a palindrome."
>> end
>>end
=> :palindrome_tester

>>palindrome_tester(s)
=>It's not a palindrome.
=> nil

>>def palindrome_tester(s)
>> if s=s.reverse
>>  puts "It's a palindrome!"
>> else
>>  puts "It's not a palindrome."
>> end
>>end
=> :palindrome_tester

>>palindrome_tester(s.split.join.downcase)
=>It's a palindrome!
=> nil

演習4.3.1.4

<問題> aからzまでの範囲オブジェクトを作成し、7番目の要素を取り出してみてください。同様にして、後ろから7番目の要素を取り出してみてください。(ヒント: 範囲オブジェクトを配列に変換するのを忘れないでください)

<解答>

>>a=('a'..'z').to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

>>a[7]
=> "h"

>>a[-7]
=> "t"

演習4.3.2

演習4.3.2.1

<問題> 範囲オブジェクト0..16を使って、各要素の2乗を出力してください。

<解答>

>>(0..16).each do |i|
>> puts i*i
>>end
0
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
=> 0..16

演習4.3.2.2

<問題> yeller (大声で叫ぶ) というメソッドを定義してください。このメソッドは、文字列の要素で構成された配列を受け取り、各要素を連結した後、大文字にして結果を返します。例えばyeller([’o’, ’l’, ’d’])と実行したとき、"OLD"という結果が返ってくれば成功です。ヒント: mapとupcaseとjoinメソッドを使ってみましょう。

<解答>

>>def yeller(s)
>> s.join.upcase
>>end
=> :yeller

>>yeller(['o', 'l', 'd'])
=> "OLD"

演習4.3.2.3

<問題> random_subdomainというメソッドを定義してください。このメソッドはランダムな8文字を生成し、文字列として返します。ヒント: サブドメインを作るときに使ったRubyコードをメソッド化したものです。

<解答>

>>def random_subdomain(a)
>> a.to_a.shuffle[0..7].join
>>end
=> :random_subdomain

>>random_subdomain('a'..'z')
=> "vjqfctag"

a~zのみではなく、0~9も含めたランダム8文字生成方法

>>a="a".."z"
=> "a".."z"

>>b=0..9
=> 0..9

>>a.to_a.concat(b.to_a)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

>>def random_subdomain(a)
>> a.to_a.shuffle[0..7].join
>>end
=> :random_subdomain

>>random_subdomain(a.to_a.concat(b.to_a))
=> "cin362ps"

concatメソッドは、配列arrayの末尾に引数の配列other_arrayを結合します。

演習4.3.2.4

<問題> リスト 4.12の「?」の部分を、それぞれ適切なメソッドに置き換えてみてください。ヒント:split、shuffle、joinメソッドを組み合わせると、メソッドに渡された文字列 (引数) をシャッフルさせることができます

<解答>

>>def string_shuffle(s)
>> s.split('').shuffle.join
>>end
=> :string_shuffle

>>string_shuffle("foobar")
=> "arobof"

演習4.3.3

演習4.3.3.1

<問題> キーが’one’、’two’、’three’となっていて、それぞれの値が’uno’、’dos’、’tres’となっているハッシュを作ってみてください。その後、ハッシュの各要素をみて、それぞれのキーと値を"’#{key}’のスペイン語は’#{value}’"といった形で出力してみてください。

<解答>

>>flash={one:"uno",two:"dos",three:"tres"}
=> {:one=>"uno", :two=>"dos", :three=>"tres"}

>>flash.each do |key, value|
>> puts "'#{key}'のスペイン語は'#{value}'"
>>end
'one'のスペイン語は'uno'
'two'のスペイン語は'dos'
'three'のスペイン語は'tres'
=> {:one=>"uno", :two=>"dos", :three=>"tres"}

演習4.3.3.2

<問題> person1、person2、person3という3つのハッシュを作成し、それぞれのハッシュに:firstと:lastキーを追加し、適当な値 (名前など) を入力してください。その後、次のようなparamsというハッシュのハッシュを作ってみてください。1.) キーparams[:father]の値にperson1を代入、2). キーparams[:mother]の値にperson2を代入、3). キーparams[:child]の値にperson3を代入。最後に、ハッシュのハッシュを調べていき、正しい値になっているか確かめてみてください。(例えばparams[:father][:first]がperson1[:first]と一致しているか確かめてみてください)

<解答>

person1={first:"suzuki",last:"ichiro"}
=> {:first=>"suzuki", :last=>"ichiro"}

person2={first:"tanaka",last:"hanako"}
=> {:first=>"tanaka", :last=>"hanako"}

person3={first:"sato",last:"takashi"}
=> {:first=>"sato", :last=>"takashi"}

params={}
=> {}

params[:father]=person1
=> {:first=>"suzuki", :last=>"ichiro"}

params[:mother]=person2
=> {:first=>"tanaka", :last=>"hanako"}

params[:child]=person3
=> {:first=>"sato", :last=>"takashi"}

params
=> {:father=>{:first=>"suzuki", :last=>"ichiro"}, :mother=>{:first=>"tanaka", :last=>"hanako"}, :child=>{:first=>"sato", :last=>"takashi"}}

params[:father][:last]
=> "ichiro"

params[:child][:first]
=> "sato"

演習4.3.3.3

<問題> userというハッシュを定義してみてください。このハッシュは3つのキー:name、:email、:password_digestを持っていて、それぞれの値にあなたの名前、あなたのメールアドレス、そして16文字からなるランダムな文字列が代入されています。

<解答>

user={name:"yamada",email:"yamada@gmail.com",password_digest:"asdfghjk12345678"}
=> {:name=>"yamada", :email=>"yamada@gmail.com", :password_digest=>"asdfghjk12345678"}

演習4.3.3.4

<問題> Ruby API (訳注: もしくはるりまサーチ) を使って、Hashクラスのmergeメソッドについて調べてみてください。次のコードを実行せずに、どのような結果が返ってくるか推測できますか? 推測できたら、実際にコードを実行して推測があっていたか確認してみましょう。

<解答>

{ "a" => 100, "b" => 200 }.merge({ "b" => 300 })
=> {"a"=>100, "b"=>300}

重複するbは引数が適用される

演習4.4.1

演習4.4.1.1

<問題> 1から10の範囲オブジェクトを生成するリテラルコンストラクタは何でしたか? (復習です)

<解答>

a=1..10
=> 1..10

演習4.4.1.2

<問題> 今度はRangeクラスとnewメソッドを使って、1から10の範囲オブジェクトを作ってみてください。ヒント: newメソッドに2つの引数を渡す必要があります

<解答>

b=Range.new(1,10)
=> 1..10

演習4.4.1.3

<問題> 比較演算子==を使って、上記2つの課題で作ったそれぞれのオブジェクトが同じであることを確認してみてください。

<解答>

a==b
=> true

演習4.4.2

演習4.4.2.1

<問題> Rangeクラスの継承階層を調べてみてください。同様にして、HashとSymbolクラスの継承階層も調べてみてください。

<解答>

Range => Class=> Module=> Object=> BasicObject

Hash,Symbolも同じ

演習4.4.2.2

<問題> リスト 4.15にあるself.reverseのselfを省略し、reverseと書いてもうまく動くことを確認してみてください。

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

演習4.4.3

演習4.4.3.1

<問題> palindrome?メソッドを使って、“racecar”が回文であり、“onomatopoeia”が回文でないことを確認してみてください。南インドの言葉「Malayalam」は回文でしょうか? ヒント: downcaseメソッドで小文字にすることを忘れないで。

<解答>

>>class String
>> def palindrome?
>>  self==reverse
>> end
>>end
=> :palindrome?

>>"racecar".palindrome?
=> true

>>"onomatopoeia".palindrome?
=> false

>>"Malayalam".downcase.palindrome?
=> true

演習4.4.3.2

<問題> リスト 4.16を参考に、Stringクラスにshuffleメソッドを追加してみてください。 ヒント: リスト 4.12も参考になります。

<解答>

class String
def shuffle
self.split('').shuffle.join
end
end
=> :shuffle
"foobar".shuffle
=> "rfooba"

演習4.4.3.3

<問題> リスト 4.16のコードにおいて、self.を削除してもうまく動くことを確認してください。

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

演習4.4.4

演習4.4.4.1

<問題> 第2章で作ったToyアプリケーションのディレクトリでRailsコンソールを開き、User.newと実行することでuserオブジェクトが生成できることを確認してみましょう。

<解答>

>>User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>

演習4.4.4.2

<問題> 生成したuserオブジェクトのクラスの継承階層を調べてみてください。

<解答>

User => Class=> Module=> Object=> BasicObject

演習4.4.5

演習4.4.5.1

<問題> Userクラスで定義されているname属性を修正して、first_name属性とlast_name属性に分割してみましょう。また、それらの属性を使って “Michael Hartl” といった文字列を返すfull_nameメソッドを定義してみてください。最後に、formatted_emailメソッドのnameの部分を、full_nameに置き換えてみましょう (元々の結果と同じになっていれば成功です)

<解答>

[example_user.rb]

class User
 attr_accessor :first_name,:last_name, :email

 def initialize(attributes = {})
  @first_name = attributes[:first_name]
  @last_name = attributes[:last_name]
  @email = attributes[:email]
 end

 def full_name
  @full_name = @first_name + @last_name
 end

 def formatted_email
  "#{@full_name} <#{@email}>"
 end
end

[console]

>>require './example_user'
=> true

>>user = User.new(first_name: "Michael", last_name: "Hartl", email: "mhartl@example.com")
=> #<User:0x00000002d21bd8 @first_name="Michael", @last_name="Hartl", 

>>@email="mhartl@example.com"
>>user.full_name
=> "MichaelHartl"

>>user.formatted_email
=> "MichaelHartl mhartl@example.com"

演習4.4.5.2

<問題> “Hartl, Michael” といったフォーマット (苗字と名前がカンマ+半角スペースで区切られている文字列) で返すalphabetical_nameメソッドを定義してみましょう。

<解答>

[example_user.rb]

class User
 attr_accessor :first_name,:last_name, :email

 def initialize(attributes = {})
  @first_name = attributes[:first_name]
  @last_name = attributes[:last_name]
  @email = attributes[:email]
 end

 def full_name
  @full_name = @first_name + @last_name
 end

 def alphabetical_name
  @alphabetical_name = "#{@first_name}, #{@last_name}"
 end

 def formatted_email_full
  "#{@full_name} <#{@email}>"
 end

 def formatted_email_al
  "#{@alphabetical_name} <#{@email}>"
 end
end

[console]

>>require './example_user'
=> true

>>user = User.new(first_name: "Michael", last_name: "Hartl", email: "mhartl@example.com")
=> #<User:0x00000003fd67b0 @first_name="Michael", @last_name="Hartl", 

>>@email="mhartl@example.com">
>>user.alphabetical_name
=> "Michael, Hartl"

>>user.formatted_email_al
=> "Michael, Hartl mhartl@example.com"

演習4.4.5.3

<問題> full_name.splitとalphabetical_name.split(’, ’).reverseの結果を比較し、同じ結果になるかどうか確認してみましょう。

<解答>

[console]

>>user.full_name.split
=> ["MichaelHartl"]

>>user.alphabetical_name.split(', ').reverse
=> ["Hartl", "Michael"]

>>user.formatted_email_full
=> "MichaelHartl mhartl@example.com"

>>user.formatted_email_al
=> "Michael, Hartl mhartl@example.com"

⇒同じになる

関連記事

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com

mochikichi.hatenablog.com