35歳だけどRailsチュートリアルやってみた。[第4版 8章 8.2 ログイン まとめ&解答例]

#はじめに
最近、プロジェクト管理業務が業務の大半を占めており、
プログラムを書く機会がなかなかありません。

このままだとプログラムがまったく書けない人になってしまう危機感（迫り来る35歳定年説）と、
新しいことに挑戦したいという思いから、
[Ruby on Rails チュートリアル実例を使ってRailsを学ぼう 第4版](https://railstutorial.jp/)を学習中です。
業務で使うのはもっぱらJavaなのですが、Rails楽しいですね。


これまでEvernoteに記録していましたが、ソースコードの貼付けに限界を感じたため、
Qiitaで自分が学習した結果をアウトプットしていきます。

個人の解答例なので、誤りがあればご指摘ください。

##8.2.1 log_inメソッド
###本章での学び
####Railsのセッション用ヘルパー
Sessionsコントローラを作成すると自動生成される。
また、ビューでも自動でインクルードされる。

Railsの全コントローラのベースクラス（Application_controller.rb）にインクルードすれば、すべてのコントローラでセッション用ヘルパーが使えるようになる。

```/sample_app/app/controllers/application_controller.rb
  include SessionsHelper
```

####sessionメソッド
Railsで事前定義済みのメソッド。ハッシュのように扱える。

`session[:user_id] = user.id`

ユーザのブラウザ内の一時cookiesに暗号化済みのユーザIDが自動で生成される。後続のページで、`session[:user_id]`を使うことで、ユーザIDを元通りに取り出せる。

`cookies`メソッドとは対照的に、`session`メソッドはブラウザを閉じた瞬間に有効期限が終了する。

####セッション用ヘルパーの修正
同じログイン手法を様々な場所で使いまわせるようにするために、セッション用ヘルパーに`log_in`メソッドを追加する。

```/sample_app/app/helpers/sessions_helper.rb
  def log_in(user)
    session[:user_id] = user.id
  end
```

`session`メソッドで暗号化した一時cookiesは、攻撃者が盗んだとしても、それを使って本物のユーザとしてログインすることはできない。（永続的な情報ではないためと思われる）

####sessionsコントローラの修正
`create`アクションを修正する。
ユーザログインを行い、ユーザのプロフィールページへリダイレクトを行う。

```/sample_app/app/controllers/sessions_controller.rb
    if user && user.authenticate(params[:session][:password])
      log_in user
      redirect_to user
```

`redirect_to user`は、Railsgが`user_url(user)`に自動的に変換する。


###演習1
*有効なユーザーで実際にログインし、ブラウザからcookiesの情報を調べてみてください。このとき、sessionの値はどうなっているでしょうか? ヒント: ブラウザでcookiesを調べる方法が分からない? 今こそググってみるときです! (コラム 1.1)*

ログインページヘアクセスする。
chromeでF12を押して開発ツールを表示して、sessionの値を確認。

![image](https://qiita-image-store.s3.amazonaws.com/0/98130/5e3aa5d0-7dfd-2b46-b9ad-15c2a1a0596c.png)


有効なユーザでログインする。

![image](https://qiita-image-store.s3.amazonaws.com/0/98130/0a146a6b-7ba8-1f40-9af7-61d7074c25af.png)



###演習2
*先ほどの演習課題と同様に、Expiresの値について調べてみてください。*

##8.2.2 現在のユーザー
###本章での学び
####current_userメソッド
セッションIDに対応する情報をデータベースから取得することができるようにする`current_user`メソッドを作成する。

例）セッションIDに対応するユーザ名を取得する。
```
<%= current_user.name %>
```

`find_by`メソッドを使うことで、nilが返ってくることを防ぐ。

```
User.find_by(id: session[:user_id])
```

####Railsの処理高速化のテクニック
`User.find_by`の実行結果を、インスタンス変数に保存することで、データベースの読み込みは1回になる。
以降はインスタンス変数を返すようになる。

```
if @current_user.nil?

```

####or equals代入演算子
`||=`という代入演算子を使うことで、or演算子を短縮して書くことができる。
javaで言うところの、`x = x + 1`を、`x += 1`と書くのと同じイメージ。

| 短縮系            |       短縮しない場合 |
|:-----------------|------------------:|
| x += 1           |       x = x +1    |
| @foo \||= "bar"   |@foo = @foo || "bar" |


*「変数の値がnilなら変数に代入するが、nilでなければ代入しない」*という操作が、Rubyではよく行われる。

####Rubyの王道
書ける処理は短縮形で書く。
or equals演算子を使うことで、以下の複数行の処理が１行で書ける。

```
if @current_user.nil?
  @current_user = User.find_by(id: session[:user_id])
else
  @current_user
end
```

上のコードと同じ意味になる。
こちらがRubyの王道。

```
@current_user ||= User.find_by(id: session[:user_id])
```

###演習1
*Railsコンソールを使って、User.find_by(id: ...)で対応するユーザーが検索に引っかからなかったとき、nilを返すことを確認してみましょう。*

ユーザIDに存在しない100を指定して検索。
nilが返ってくることを確認。

```
>> User.find_by(id: '100')
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 100], ["LIMIT", 1]]
=> nil
```

###演習2
*先ほどと同様に、今度は:user_idキーを持つsessionハッシュを作成してみましょう。リスト 8.17に記したステップにしたがって、||=演算子がうまく動くことも確認してみましょう。*

ユーザIDが１のユーザ情報をもとに、sessionハッシュを生成する。

```
?> user = User.find_by(id: '1')
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2017-05-07 21:50:35", updated_at: "2017-05-07 21:50:35", password_digest: "$2a$10$esrzyVS.n7KGJ27bcs7UF.78tD7e75pMkwy6gnnwhlQ...">
>> session = { user_id: user.name, name: user.name, email: user.email }
=> {:user_id=>"Rails Tutorial", :name=>"Rails Tutorial", :email=>"example@railstutorial.org"}
```

リストの手順に従い、||=演算子を検証する。
ユーザーIDが1（というか最初のユーザ）でハッシュを生成する場合は、
`session[:user_id] = User.first.id`でハッシュを生成したほうが楽。

```
?> session = {}
=> {}
>> session[:user_id] = nil
=> nil
>> @current_user ||= User.find_by(id: session[:user_id])
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ?  [["LIMIT", 1]]
=> nil
>> session[:user_id] = User.first.id
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 1
>> @current_user ||= User.find_by(id: session[:user_id])
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2017-05-07 21:50:35", updated_at: "2017-05-07 21:50:35", password_digest: "$2a$10$esrzyVS.n7KGJ27bcs7UF.78tD7e75pMkwy6gnnwhlQ...">
>> @current_user ||= User.find_by(id: session[:user_id])
=> #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2017-05-07 21:50:35", updated_at: "2017-05-07 21:50:35", password_digest: "$2a$10$esrzyVS.n7KGJ27bcs7UF.78tD7e75pMkwy6gnnwhlQ...">
```


##8.2.3 レイアウトリンクを変更する
###本章での学び

####ログアウト用リンク
ログアウト用のリンクは以下の通り、引数に`method: : delete`を渡している。
Webブラウザは実際にはDELETEリクエストを発行できないため、RailsではJavaScriptを使って偽装している。

```
<%= link_to "Log out", logout_path, method: :delete%>
```

####ユーザプロフィール用リンク
省略形で`current_user`を使う。

```
<%= link_to "Profile", current_user %>
```

Railsによって、以下のコードに自動変換される。

```
<%- link_to "Profile", user_path(current_user) %>
```

####ドロップダウンメニューの作成
bootstrapの`dropdown`クラスや、`dropdown-menu`にて実現する。
これらのクラスを実装しただけでは、ドロップダウンメニューは表示されない。

![image](https://qiita-image-store.s3.amazonaws.com/0/98130/e7e3fefb-03e0-422c-6f33-0b029f6169e6.png)

####bootstrapを有効にする
ドロップダウンメニューを有効にするために、`application.js`にBootstrapのカスタムjsをインクルードするように指定する必要がある。

```/sample_app/app/assets/javascripts/application.js
//= require bootstrap
```

railsを再起動すると、ドロップダウンメニューが表示される。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/98130/5eacf8e6-219c-50de-20d3-d09469430a58.png)

###演習1
*ブラウザのcookieインスペクタ機能を使って (8.2.1.1)、セッション用のcookieを削除してみてください。ヘッダー部分にあるリンクは非ログイン状態のものになっているでしょうか? 確認してみましょう。*

chromeの開発ツールでcookie情報を表示する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/98130/1a7d6a1b-7980-46f5-bd8d-2bc8391030ed.png)

右クリック=>`clear`でcookieを削除して、F5で更新。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/98130/937a9307-7593-3cfc-050f-26d9154dc30f.png)

ヘッダー部にあるリンクが非ログイン状態になることを確認。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/98130/a094c794-9cec-fecd-122b-53aa5ff4b4a8.png)


###演習2
*もう一度ログインしてみて、ヘッダーのレイアウトが変わったことを確認してみましょう。その後、ブラウザを再起動させ、再び非ログイン状態に戻ったことも確認してみてください。注意: もしブラウザの [閉じたときの状態に戻す] 機能をオンにしていると、セッション情報も復元される可能性があります。もしその機能をオンにしている場合、忘れずにオフにしておきましょう (コラム 1.1)。*

再度ログイン。ヘッダーのレイアウトが変わることを確認。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/98130/082281f5-ab0d-b525-c50b-45829cb69f5c.png)

ブラウザをxで閉じてから再起動。ヘッダーのレイアウトがログイン前に戻ることを確認。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/98130/82ada0ec-5196-cc56-ff29-1eb78c6a2bdc.png)


##8.2.4 レイアウトの変更をテストする
###本章での学び
####テスト用データを生成する
*fixture*ファイルで作成することができる。
テストに必要なデータをtestデータベースに読み込んでおくことが可能。


####fixture向けのdigestメソッドを定義する
fixtureで有効なメールアドレス、名前を設定しておく。
テスト中にそのユーザとしてログインするために、そのユーザの有効なパスワードも設定しておく。
*password_digest*属性をユーザのfixtureに追加するために、`User`モデル内に、独自の`digest`メソッドを追加する。

#####bcryptによるパスワードのハッシュ化
`has_secure_password`でbcryptのパスワードが生成されるため、同様の仕組みにする。

`BCrypt::Password.create(string, cost: cost)`

`string`は、ハッシュ化する文字列。
`cost`は、コストパラメータ。ハッシュを算出するための計算コストを指定する。コストパラメータの値を高くすることで、ハッシュからオリジナルのパスワードを計算で算出することは困難になる。

#####三項演算子によるコストパラメータの計算
テストにおいてはコストパラメータを高くする意味はない。
三項演算子で記載された`has_secure_password`内の実装を参考にする。

参考演算子とは、

```
  if boolean?
    何かをする
  else
    別のことをする
  end
```

上記の分岐を、１行で記載することができる。

```
  論理値? ? 何かをする : 別のことをする
```

上記を踏まえ、`has_secure_password`内の実装を見ると、`ActiveModel::SecurePassword.min_cost`がtrueなら、`BCrypt::Engine::MIN_COST`を使用する。つまり、テスト中はコストを最小にして、本番ではコストを明確に指定して計算する。

```
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                              BCrypt::Engine.cost
```

#####クラスメソッドとインスタンスメソッド
クラスメソッドは、*クラスオブジェクトから実行可能なメソッド*
（Javaで言うところのstaticメソッド）

`def self.method_name`で定義する。
今回の`digest`メソッドも、クラスメソッドで定義している。
（ユーザーごとのインスタンスで計算する必要はないため、インスタンスメソッドではなくクラスメソッドにしている）


インスタンスメソッドは、*インスタンスオブジェクトから実行可能なメソッド*

違いは以下を参照。
http://qiita.com/tbpgr/items/56eb65c0ea5882abbb07


####ユーザーログインのテストで使うfixture
名前、メールアドレス、パスワードを定義する。
fixtureの中では、ERbを使用することができる。

```/sample_app/test/fixtures/users.yml
michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>
```

####fixtureの生パスワード
fixture内で`password`属性を指定することはできない（DBのカラムにもpasswordがいない）ため、テストケース内で直接記載する。

fixtureのユーザが増えても、全員、同じパスワードの値（今回はpassword）を使用する。


####テストシナリオのコード化
0.事前準備
`users`とは、fixtureのファイル名`users.yml`のこと。
`users.yml`から、michaelユーザの情報を読み込み、インスタンス変数へ格納する。

```/sample_app/test/integration/users_login_test.rb
def setup
  @user = users(:michael)
end
```

1.ログイン用のパスを開く
`get login_path`

2.セッション用パスに有効な情報をpostする
`assert_redirected_to @user`で、リダイレクト先が正しいかを確認する。
`follow_redirect!`で、実際にリダイレクトする。

```
post login_path, params: { session: { email: @user.email,
                                      password: 'password' } }
assert_redirected_to @user
follow_redirect!
assert_template 'users/show'
```

3.ログイン用リンクが表示されなくなったことを確認する
`count: 0`を付与することで、`assert_select`に渡したパターンに一致するリンクが０可動化を確認する。
`assert_select "a[href=?]", login_path, count: 0`

4.ログアウト用リンクが表示されていることを確認する
`assert_select "a[href=?]", logout_path`

5.プロフィール用リンクが表示されていることを確認する
`assert_select "a[href=?], user_path(@user)"`

####テストファイル内の特定のテストのみ実行する
テストファイル内に複数のテストシナリオが存在する場合、テストファイル名とテスト名を指定することができる。

`--name`で指定するテスト名は、接頭語に「test_」をつけて、test '...' doの部分の単語をアンダースコアでつないだ文字列で指定する。

```/sample_app/test/integration/users_login_test.rb
  test "login with valid information" do
    ・・・略
  end
```

```
yokoyan:~/workspace/sample_app (basic-login) $ rails test test/integration/users_login_test.rb --name test_login_with_valid_information
Running via Spring preloader in process 3098
Started with run options --name test_login_with_valid_information --seed 3699

  1/1: [=====================================================================================================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.82456s
1 tests, 6 assertions, 0 failures, 0 errors, 0 skips
```


###演習1
*試しにSessionヘルパーのlogged_in?メソッドから!を削除してみて、リスト 8.23が redになることを確認してみましょう。*

```/sample_app/app/helpers/sessions_helper.rb
  #ユーザーがログインしていればtrue、その他ならfalseを返す
  def logged_in?
    # !current_user.nil?
    current_user.nil?
  end
```

テスト結果がredになることを確認。
ユーザーがログインしていても、trueを返せないためredになっている。

```
yokoyan:~/workspace/sample_app (basic-login) $ rails test test/integration/users_login_test.rb --name test_login_with_valid_information
Running via Spring preloader in process 3164
Started with run options --name test_login_with_valid_information --seed 35997

 FAIL["test_login_with_valid_information", UsersLoginTest, 0.8784956429954036]
 test_login_with_valid_information#UsersLoginTest (0.88s)
        Expected exactly 0 elements matching "a[href="/login"]", found 1..
        Expected: 0
          Actual: 1
        test/integration/users_login_test.rb:29:in `block in <class:UsersLoginTest>'

  1/1: [=====================================================================================================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.88460s
1 tests, 4 assertions, 1 failures, 0 errors, 0 skips
```

###演習2
*先ほど削除した部分 (!) を元に戻して、テストが greenに戻ることを確認してみましょう。*

修正箇所をもとに戻す。

```
  #ユーザーがログインしていればtrue、その他ならfalseを返す
  def logged_in?
    !current_user.nil?
  end
```

テスト結果がgreenになることを確認。

```
yokoyan:~/workspace/sample_app (basic-login) $ rails test test/integration/users_login_test.rb --name test_login_with_valid_information
Running via Spring preloader in process 3246
Started with run options --name test_login_with_valid_information --seed 37023

  1/1: [=====================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.02458s
1 tests, 6 assertions, 0 failures, 0 errors, 0 skips
```

##8.2.5 ユーザー登録時にログイン
###本章での学び
####ユーザー登録時にログインする
`Users`コントローラの、`create`メソッド内で、`log_in @user`を追加すればOK。
Sessionsコントローラがあることで、Usersコントローラでも`SessionsHelper`で定義している`log_in`メソッドが使える。

正確には、`application_controller.rb`内で、`SessionsHelper`をインクルードしているため、Usersコントローラでも`log_in`メソッドが使える。

```/sample_app/app/controllers/users_controller.rb
  def create
    @user = User.new(user_params)
    if @user.save
      log_in(@user)
      ・・・略
  end
```

####テストヘルパーメソッドの修正
ログイン中かどうかを確認するテストを追加する。
ログイン中かどうかの判定は、`sessions_helper.rb`で定義したヘルパーメソッド、`logged_in?`で取得できる。

```/sample_app/app/helpers/sessions_helper.rb
  # 現在ログイン中のユーザーを返す (いる場合)
  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end

  # ユーザーがログインしていればtrue、その他ならfalseを返す
  def logged_in?
    !current_user.nil?
  end
```

しかし、ヘルパーメソッドはテスト内から呼び出すことができない。
そのため、`test_helper.rb`内に新しく、`is_logged_in?`を定義する。
sessionヘルパー内の`current_user`を呼び出せないため、代わりに`session`メソッドを使って実現する。

```/sample_app/test/test_helper.rb
  # テストユーザーがログイン中の場合にtrueを返す
  def is_logged_in?
    !session[:user_id].nil?
  end
```


####ユーザー登録後のログインのテスト
1.ユーザー登録画面のパスを開く

```
 get signup_path
```

2.ユーザー登録情報をpostして、ユーザー登録数が１増えているかを確認する

```
  assert_difference 'User.count', 1 do
    post users_path , params: { { name: "Example User",
                                  email: "user@example.com",
                                  password: "password",
                                  password_confirmation: "password" }}
  end
```

3.リダイレクトする

```
  follow_redirect!
```

4.ユーザー情報表示画面のテンプレートが表示されることを確認する

```
  assert_template 'users/show'
```

5.フラッシュメッセージ（エラーメッセージ）が無いことを確認する

```
  assert_not flash.empty?
```

6.ログイン中かどうかを確認する
定義した`is_logged_in?`ヘルパーメソッドを呼び出す。

```
  assert is_logged_in?
```


###演習1
*リスト 8.25のlog_inの行をコメントアウトすると、テストスイートは red になるでしょうか? それとも green になるでしょうか? 確認してみましょう。*

log_inをコメントアウトしてテストを実行。

```/sample_app/app/controllers/users_controller.rb
    if @user.save
      #log_in(@user)
```

redになることを確認。
原因はユーザ登録後、ログインしていないため。
`assert is_logged_in?`でエラーになっている。

```
yokoyan:~/workspace/sample_app (basic-login) $ rails test
Running via Spring preloader in process 2623
Started with run options --seed 59224

 FAIL["test_valid_signup_information", UsersSignupTest, 1.0323550210014218]
 test_valid_signup_information#UsersSignupTest (1.03s)
        Expected false to be truthy.
        test/integration/users_signup_test.rb:39:in `block in <class:UsersSignupTest>'

  23/23: [===================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.47616s
23 tests, 63 assertions, 1 failures, 0 errors, 0 skips
```

コメントアウトを戻すとgreenになることを確認。

###演習2
*現在使用しているテキストエディタの機能を使って、リスト 8.25をまとめてコメントアウトできないか調べてみましょう。また、コメントアウトの前後でテストスイートを実行し、コメントアウトすると red に、コメントアウトを元に戻すと green になることを確認してみましょう。ヒント: コメントアウト後にファイルを保存することを忘れないようにしましょう。また、テキストエディタのコメントアウト機能については Test Editor Tutorial の Commenting Out (英語) などを参照してみてください。*

cloud9の場合、`Ctrl+/`で複数行コメントアウトできる。
もちろんテストはredになる。

```
yokoyan:~/workspace/sample_app (basic-login) $ rails test
Running via Spring preloader in process 2723
Started with run options --seed 55337

ERROR["test_layout_links", SiteLayoutTest, 0.8837061480007833]
 test_layout_links#SiteLayoutTest (0.88s)
ActionView::Template::Error:         ActionView::Template::Error: First argument in form cannot contain nil or be empty
            app/views/users/new.html.erb:6:in `_app_views_users_new_html_erb__3664408681092639721_27399160'
            test/integration/site_layout_test.rb:17:in `block in <class:SiteLayoutTest>'

ERROR["test_invalid_signup_information", UsersSignupTest, 0.9015909680019831]
 test_invalid_signup_information#UsersSignupTest (0.90s)
ActionView::Template::Error:         ActionView::Template::Error: First argument in form cannot contain nil or be empty
            app/views/users/new.html.erb:6:in `_app_views_users_new_html_erb__3664408681092639721_26560060'
            test/integration/users_signup_test.rb:9:in `block in <class:UsersSignupTest>'

ERROR["test_valid_signup_information", UsersSignupTest, 0.916260575002525]
 test_valid_signup_information#UsersSignupTest (0.92s)
ActionView::Template::Error:         ActionView::Template::Error: First argument in form cannot contain nil or be empty
            app/views/users/new.html.erb:6:in `_app_views_users_new_html_erb__3664408681092639721_25494440'
            test/integration/users_signup_test.rb:29:in `block in <class:UsersSignupTest>'

ERROR["test_login_with_valid_information", UsersLoginTest, 1.090877412003465]
 test_login_with_valid_information#UsersLoginTest (1.09s)
ActionView::Template::Error:         ActionView::Template::Error: undefined method `name' for nil:NilClass
            app/views/users/show.html.erb:1:in `_app_views_users_show_html_erb___1927824141870267168_46476740'
            test/integration/users_login_test.rb:27:in `block in <class:UsersLoginTest>'

ERROR["test_should_get_new", UsersControllerTest, 1.1993190759967547]
 test_should_get_new#UsersControllerTest (1.20s)
ActionView::Template::Error:         ActionView::Template::Error: First argument in form cannot contain nil or be empty
            app/views/users/new.html.erb:6:in `_app_views_users_new_html_erb__3664408681092639721_38933240'
            test/controllers/users_controller_test.rb:5:in `block in <class:UsersControllerTest>'

  23/23: [===================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.20674s
23 tests, 43 assertions, 0 failures, 5 errors, 0 skips
```

再度コメントアウトを戻して、テストがgreenになることを確認。

```
yokoyan:~/workspace/sample_app (basic-login) $ rails test
Running via Spring preloader in process 2801
Started with run options --seed 61736

  23/23: [===================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.26744s
23 tests, 63 assertions, 0 failures, 0 errors, 0 skips
```

#おわりに
ユーザ登録、ログイン機能がひと通り完成しました。
RailsはSQLを意識しなくても、データベースのCRUD処理ができてしまうのがすごいなあと感じます。
その分、中で何が起こっているのかを理解するために、もう一歩踏み込みながら学習したいと思います。