##前提
・Railsチュートリアルは第4版
・今回の学習は3周目(9章以降は2周目)
・著者はProgate一通りやったぐらいの初学者
##基本方針
・読んだら分かることは端折る。
・意味がわからない用語は調べてまとめる(記事最下段・用語集)。
・理解できない内容を掘り下げる。
・演習はすべて取り組む。
・コードコピペは極力しない。
ラストじゃ!!!!!最後まで駆け抜けろ!!!!!
ラストを飾るBGMはこちら。
My Bloody Valentine "Loveless"
始まりにして終わりみたいな一枚。もはやオチ担当。大音量で脳汁たらしながら聴きましょう。
####【14.1.1 データモデルの問題(および解決策) 演習】
1. 図 14.7のid=1のユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。ヒント: 4.3.2で紹介したmap(&:method_name)のパターンを思い出してください。例えばuser.following.map(&:id)の場合、idの配列を返します。
→ これって、この時点でコンソール上で実行してもnomethoderrorでいいですよね?following定義してないし。(なんで演習解答まとめにみんな載せてないんだ?)
想像としては、id:1のユーザーがフォローしているユーザーのidの配列が返される。
2. 図 14.7を参考にして、id=2のユーザーに対してuser.followingを実行すると、結果はどのようになるでしょうか? また、同じユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。
→ ユーザー2がフォローしているユーザーのid(ここでは1)を返す。後者はその配列。
####【14.1.2 User/Relationshipの関連付け 演習】
1. コンソールを開き、表 14.1のcreateメソッドを使ってActiveRelationshipを作ってみましょう。データベース上に2人以上のユーザーを用意し、最初のユーザーが2人目のユーザーをフォローしている状態を作ってみてください。
→ 下記
>> user = User.first
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2020-09-21 06:47:51", updated_at: "2020-09-21 06:47:51", password_digest: "$2a$10$nAPmDn2RaEHJcHlMrK2PK.nOxUN4ULh7yUHchZRZtSZ...", remember_digest: nil, admin: true, activation_digest: "$2a$10$l9hNDaXUmopBnprlT0H7J.YFieEB8U9OoNgA0mzcrPS...", activated: true, activated_at: "2020-09-21 06:47:51", reset_digest: nil, reset_sent_at: nil>
>> other_user = 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: "Ms. Jerry Hermann", email: "example-1@railstutorial.org", created_at: "2020-09-21 06:47:52", updated_at: "2020-09-21 06:47:52", password_digest: "$2a$10$4n7IPw3AcdhW6IzNuLygIuVLA26qlTNneHXDXIqW0zp...", remember_digest: nil, admin: false, activation_digest: "$2a$10$QNHMG3qKng0pFdQdDfGNMeFZaDiddcT0z3ovdEVcOcn...", activated: true, activated_at: "2020-09-21 06:47:52", reset_digest: nil, reset_sent_at: nil>
>> user.active_relationships.create(followed_id: other_user.id)
(0.1ms) SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
SQL (3.4ms) INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["follower_id", 1], ["followed_id", 2], ["created_at", "2020-09-23 12:37:03.376561"], ["updated_at", "2020-09-23 12:37:03.376561"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2020-09-23 12:37:03", updated_at: "2020-09-23 12:37:03">
2. 先ほどの演習を終えたら、active_relationship.followedの値とactive_relationship.followerの値を確認し、それぞれの値が正しいことを確認してみましょう。
→ 上の解答の一番下に出てます。
####【14.1.3 Relationshipのバリデーション 演習】
1. リスト 14.5のバリデーションをコメントアウトしても、テストが成功したままになっていることを確認してみましょう。(以前のRailsのバージョンでは、このバリデーションが必須でしたが、Rails 5から必須ではなくなりました。今回はフォロー機能の実装を優先しますが、この手のバリデーションが省略されている可能性があることを頭の片隅で覚えておくと良いでしょう。)
→ GREENでした。
####【14.1.4 フォローしているユーザー メモと演習】
has_many :配列の名称, through: :テーブル名称, source: :配列の元の集合 …なんかややこしいな。元から呼び名で使う名称の方で定義付けしとけばよかったのでは?疑問。
1. コンソールを開き、リスト 14.9のコードを順々に実行してみましょう。
→ 下記。うまくいってます。
>> user = User.first
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2020-09-21 06:47:51", updated_at: "2020-09-21 06:47:51", password_digest: "$2a$10$nAPmDn2RaEHJcHlMrK2PK.nOxUN4ULh7yUHchZRZtSZ...", remember_digest: nil, admin: true, activation_digest: "$2a$10$l9hNDaXUmopBnprlT0H7J.YFieEB8U9OoNgA0mzcrPS...", activated: true, activated_at: "2020-09-21 06:47:51", reset_digest: nil, reset_sent_at: nil>
>> other_user = User.second
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ? [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Ms. Jerry Hermann", email: "example-1@railstutorial.org", created_at: "2020-09-21 06:47:52", updated_at: "2020-09-21 06:47:52", password_digest: "$2a$10$4n7IPw3AcdhW6IzNuLygIuVLA26qlTNneHXDXIqW0zp...", remember_digest: nil, admin: false, activation_digest: "$2a$10$QNHMG3qKng0pFdQdDfGNMeFZaDiddcT0z3ovdEVcOcn...", activated: true, activated_at: "2020-09-21 06:47:52", reset_digest: nil, reset_sent_at: nil>
>> user.following?(other_user)
User Exists (0.6ms) SELECT 1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ? [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> false
>> user.follow(other_user)
(0.1ms) SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
SQL (6.4ms) INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["follower_id", 1], ["followed_id", 2], ["created_at", "2020-09-23 14:03:47.235565"], ["updated_at", "2020-09-23 14:03:47.235565"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? LIMIT ? [["follower_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 2, name: "Ms. Jerry Hermann", email: "example-1@railstutorial.org", created_at: "2020-09-21 06:47:52", updated_at: "2020-09-21 06:47:52", password_digest: "$2a$10$4n7IPw3AcdhW6IzNuLygIuVLA26qlTNneHXDXIqW0zp...", remember_digest: nil, admin: false, activation_digest: "$2a$10$QNHMG3qKng0pFdQdDfGNMeFZaDiddcT0z3ovdEVcOcn...", activated: true, activated_at: "2020-09-21 06:47:52", reset_digest: nil, reset_sent_at: nil>]>
>> user.following?(other_user)
User Exists (0.2ms) SELECT 1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ? [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> true
>> user.unfollow(other_user)
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ? [["follower_id", 1], ["followed_id", 2], ["LIMIT", 1]]
(0.1ms) SAVEPOINT active_record_1
SQL (0.2ms) DELETE FROM "relationships" WHERE "relationships"."id" = ? [["id", 1]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2020-09-23 14:03:47", updated_at: "2020-09-23 14:03:47">
>> user.following?(other_user)
User Exists (0.2ms) SELECT 1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ? [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> false
2. 先ほどの演習の各コマンド実行時の結果を見返してみて、実際にはどんなSQLが出力されたのか確認してみましょう。
→ 上のとおり。INSERTしたりDELETEしたり。
####【14.1.5 フォロワー メモと演習】
あーそうか。前節でわざわざthroughとsource使ってたのは、一個のテーブルを別々の側面から扱うためか。それにしてもfollowed_idは分かりにくいけど。
1. コンソールを開き、何人かのユーザーが最初のユーザーをフォローしている状況を作ってみてください。最初のユーザーをuserとすると、user.followers.map(&:id)の値はどのようになっているでしょうか?
→ 下記
>> user = User.first
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2020-09-21 06:47:51", updated_at: "2020-09-21 06:47:51", password_digest: "$2a$10$nAPmDn2RaEHJcHlMrK2PK.nOxUN4ULh7yUHchZRZtSZ...", remember_digest: nil, admin: true, activation_digest: "$2a$10$l9hNDaXUmopBnprlT0H7J.YFieEB8U9OoNgA0mzcrPS...", activated: true, activated_at: "2020-09-21 06:47:51", reset_digest: nil, reset_sent_at: nil>
>> other1 = 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: "Ms. Jerry Hermann", email: "example-1@railstutorial.org", created_at: "2020-09-21 06:47:52", updated_at: "2020-09-21 06:47:52", password_digest: "$2a$10$4n7IPw3AcdhW6IzNuLygIuVLA26qlTNneHXDXIqW0zp...", remember_digest: nil, admin: false, activation_digest: "$2a$10$QNHMG3qKng0pFdQdDfGNMeFZaDiddcT0z3ovdEVcOcn...", activated: true, activated_at: "2020-09-21 06:47:52", reset_digest: nil, reset_sent_at: nil>
>> other2 = User.third
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ? [["LIMIT", 1], ["OFFSET", 2]]
=> #<User id: 3, name: "Bernice Rippin", email: "example-2@railstutorial.org", created_at: "2020-09-21 06:47:52", updated_at: "2020-09-21 06:47:52", password_digest: "$2a$10$fsftEGHfcujlrAy4h.X2VelOSKNXNDnk71MbkBPOqSA...", remember_digest: nil, admin: false, activation_digest: "$2a$10$4DlqqHWVesXipOA4xC/XAOlA70S8T6PjkH3/T4RAI7M...", activated: true, activated_at: "2020-09-21 06:47:52", reset_digest: nil, reset_sent_at: nil>
>> other1.follow(user)
(0.1ms) SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
SQL (0.1ms) INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["follower_id", 2], ["followed_id", 1], ["created_at", "2020-09-23 22:04:23.011442"], ["updated_at", "2020-09-23 22:04:23.011442"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? LIMIT ? [["follower_id", 2], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2020-09-21 06:47:51", updated_at: "2020-09-21 06:47:51", password_digest: "$2a$10$nAPmDn2RaEHJcHlMrK2PK.nOxUN4ULh7yUHchZRZtSZ...", remember_digest: nil, admin: true, activation_digest: "$2a$10$l9hNDaXUmopBnprlT0H7J.YFieEB8U9OoNgA0mzcrPS...", activated: true, activated_at: "2020-09-21 06:47:51", reset_digest: nil, reset_sent_at: nil>]>
>> other2.follow(user)
(0.1ms) SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
SQL (0.1ms) INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["follower_id", 3], ["followed_id", 1], ["created_at", "2020-09-23 22:04:33.583218"], ["updated_at", "2020-09-23 22:04:33.583218"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? LIMIT ? [["follower_id", 3], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2020-09-21 06:47:51", updated_at: "2020-09-21 06:47:51", password_digest: "$2a$10$nAPmDn2RaEHJcHlMrK2PK.nOxUN4ULh7yUHchZRZtSZ...", remember_digest: nil, admin: true, activation_digest: "$2a$10$l9hNDaXUmopBnprlT0H7J.YFieEB8U9OoNgA0mzcrPS...", activated: true, activated_at: "2020-09-21 06:47:51", reset_digest: nil, reset_sent_at: nil>]>
>> user.followers.map(&:id)
User Load (0.2ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ? [["followed_id", 1]]
=> [2, 3]
2. 上の演習が終わったら、user.followers.countの実行結果が、先ほどフォローさせたユーザー数と一致していることを確認してみましょう。
→ 下記
>> user.followers.count
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ? [["followed_id", 1]]
=> 2
3. user.followers.countを実行した結果、出力されるSQL文はどのような内容になっているでしょうか? また、user.followers.to_a.countの実行結果と違っている箇所はありますか? ヒント: もしuserに100万人のフォロワーがいた場合、どのような違いがあるでしょうか? 考えてみてください。
→ SQLは上のとおり。配列作る手間分、時間と負荷がかかるのでは。なのでcountのみの方が良い。
>> user.followers.to_a.count
=> 2
####【14.2.1 フォローのサンプルデータ 演習】
1. コンソールを開き、User.first.followers.countの結果がリスト 14.14で期待している結果と合致していることを確認してみましょう。
→ 3~48なんで期待どおり。
>> User.first.followers.count
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ? [["followed_id", 1]]
=> 38
2. 先ほどの演習と同様に、User.first.following.countの結果も合致していることを確認してみましょう。
→ こちらもOK
>> User.first.following.count
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? [["follower_id", 1]]
=> 49
####【14.2.2 統計と[Follow]フォーム メモと演習】
メンバールーティング:RESTfulなルーティングに新たなルーティングを追加できる。memberはブロックの形をとる。ユーザーidが含まれたURLを扱う。idを指定しない場合はcollectionを使う。
1. ブラウザから /users/2 にアクセスし、フォローボタンが表示されていることを確認してみましょう。同様に、/users/5 では [Unfollow] ボタンが表示されているはずです。さて、/users/1 にアクセスすると、どのような結果が表示されるでしょうか?
→ プロフィールページが表示される
2. ブラウザからHomeページとプロフィールページを表示してみて、統計情報が正しく表示されているか確認してみましょう。
→ 両方ともstatsが表示されています。
3. Homeページに表示されている統計情報に対してテストを書いてみましょう。ヒント: リスト 13.28で示したテストに追加してみてください。同様にして、プロフィールページにもテストを追加してみましょう。
→ 下記。これ調べてみると、@user.active(またはpassive)_relationshipsって書いてるのが出てきたんですが、どっちもいけるんでしょうか?コンソールで試したところ、両方とも同じ結果が返されましたが、relationshipsの方が処理が少ないからいいのかも?
test "stats" do
log_in_as(@user)
get root_path
assert_match @user.following.count.to_s, response.body
assert_match @user.followers.count.to_s, response.body
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.following.count.to_s, response.body
assert_match @user.followers.count.to_s, response.body
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
>> user.active_relationships.count
(0.1ms) SELECT COUNT(*) FROM "relationships" WHERE "relationships"."follower_id" = ? [["follower_id", 1]]
=> 49
>> user.following.count
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? [["follower_id", 1]]
=> 49
####【14.2.3 [Following]と[Followers]ページ 演習】
1. ブラウザから /users/1/followers と /users/1/following を開き、それぞれが適切に表示されていることを確認してみましょう。サイドバーにある画像は、リンクとしてうまく機能しているでしょうか?
→ おーけーでーす
2. リスト 14.29のassert_selectに関連するコードをコメントアウトしてみて、テストが正しく red に変わることを確認してみましょう。
→ あれ?REDにならない?…あ、そうか。renderもコメントアウトしなきゃでした。@usersのブロックだけコメントアウトしてた。下記。
<% provide(:title, @title) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<%= gravatar_for @user %>
<h1><%= @user.name %></h1>
<span><%= link_to "view my profile", @user %></span>
<span><b>Microposts:</b><%= @user.microposts.count %></span>
</section>
<section class="stats">
<%= render 'shared/stats' %>
<% if @users.any? %>
<div class="user_avatars">
<%# @users.each do |user| %>
<%#= link_to gravatar_for(user, size: 30), user %>
<%# end %>
</div>
<% end %>
</section>
</aside>
<div class="col-md-8">
<h3><%= @title %></h3>
<% if @users.any? %>
<ul class="users follow">
<%#= render @users %>
</ul>
<%= will_paginate %>
<% end %>
</div>
</div>
####【14.2.4 [Follow]ボタン(基本編) 演習】
1. ブラウザ上から /users/2 を開き、[Follow] と [Unfollow] を実行してみましょう。うまく機能しているでしょうか?
→ うまくいってます!
2. 先ほどの演習を終えたら、Railsサーバーのログを見てみましょう。フォロー/フォロー解除が実行されると、それぞれどのテンプレートが描画されているでしょうか?
→ Rendering users/show.html.erb within layouts/application
####【14.2.5 [Follow]ボタン(Ajax編) メモと演習】
Ajaxの実装:
①form_forにremote: trueを記入。
②コントローラのアクション内にrespond_toメソッドを記入。Ajaxリクエストを受け取る。
③ブラウザ側でJSが無効になっている場合用に、config/application.rbファイルにそれ用の記述を追記。
④アクション名.js.erbにjQueryを記入。
jQuery忘れたなぁ……progateで復習してくるか。
1. ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。
→ うん、動いてます。
2. 先ほどの演習で確認が終わったら、Railsサーバーのログを閲覧し、フォロー/フォロー解除を実行した直後のテンプレートがどうなっているか確認してみましょう。
→ Rendering relationships/create.js.erb
Rendering relationships/destroy.js.erb
####【14.2.6 フォローをテストする メモと演習】
xhr: true を入れるだけでAjaxの動作をテストできる。
1. リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか?
→ format.html { redirect_to @user } のところでunknownformatが出ました。
2. リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。
→ どこまで削除すればいいのか分からないけど、文法が変にならないように削除すればGREENです。
JSが無効なときに表示するフォーマットがないからでしょうか。(先ほどの演習というのは、演習1のことなのか、それともこの直近の削除のことをいっているのか、あいまいですね…)
####【14.3.1 動機と計画 演習】
1. マイクロポストのidが正しく並んでいると仮定して (すなわち若いidの投稿ほど古くなる前提で)、図 14.22のデータセットでuser.feed.map(&:id)を実行すると、どのような結果が表示されるでしょうか? 考えてみてください。ヒント: 13.1.4で実装したdefault_scopeを思い出してください。
→ 投稿日時が新しいもの順で、各投稿のユーザーidの配列が返される?(自分自身とフォローしているユーザーのもののみ)
####【14.3.2 フィードを初めて実装する 演習】
1. リスト 14.44において、現在のユーザー自身の投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?
→ ("user_id IN (?) OR user_id = ?", following_ids, id) の構成が分かれば解けますね。先の(?)に対応するのがfollowing_ids、後の?に対応するのが、idです。ということで、それぞれセットで消せば望んだエラーが返ってきます。今回は後者のセットを削除すると、# 自分自身の投稿を確認 のコメントアウト以下3行のFAILが返ってきます。
def feed
Micropost.where("user_id IN (?)", following_ids)
end
2. リスト 14.44において、フォローしているユーザーの投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?
→ 1の逆。前者のセットを消します。# フォローしているユーザーの投稿を確認 以下の3行のFAILが返ってきます。
3. リスト 14.44において、フォローしていないユーザーの投稿を含めるためにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか? ヒント: 自分自身とフォローしているユーザー、そしてそれ以外という集合は、いったいどういった集合を表すのか考えてみてください。
→ これって、要は全マイクロポストってことですよね。ということで下記。FAILは最後の# フォローしていないユーザーの投稿を確認 です。
def feed
Micropost.all
end
####【14.3.3 サブセレクト 演習】
1. Homeページで表示される1ページ目のフィードに対して、統合テストを書いてみましょう。リスト 14.49はそのテンプレートです。
→下記。assert_matchにお約束のresponse.body、となればマイクロポストの中身が表示されているかどうかをテスト。
test "feed on Home page" do
get root_path
@user.feed.paginate(page: 1).each do |micropost|
assert_match CGI.escapeHTML(micropost.content), response.body
end
end
2. リスト 14.49のコードでは、期待されるHTMLをCGI.escapeHTMLメソッドでエスケープしています (このメソッドは11.2.3で扱ったCGI.escapeと同じ用途です)。このコードでは、なぜHTMLをエスケープさせる必要があったのでしょうか? 考えてみてください。ヒント: 試しにエスケープ処理を外して、得られるHTMLの内容を注意深く調べてください。マイクロポストの内容が何かおかしいはずです。また、ターミナルの検索機能 (Cmd-FもしくはCtrl-F) を使って「sorry」を探すと原因の究明に役立つはずです。
→ うわ、テストしたらえげつない量のエラー文出てきた。sorryで検索すると、「Your words made sense, but your sarcastic tone did not.」=「あなたの言葉は理にかなっていますが、あなたの皮肉な口調はそうではありませんでした。」 ジョークみたいなこと言われてますが、つまりエスケープしないと表示できないものがあるよってことでしょうか。
###第14章まとめ
・モデルにhas_manyを設定してテーブルの要素を柔軟に名付けて扱える。
・ルーティングはネストして、リソースに新たなものを追加できる。
・jQueryを使ってフォームにAjaxを採用。
・必要に応じてSQLも使える。
・チュートリアルはチュートリアルにすぎない。やっとスタートラインに立てたぐらいだと心得よ(自分への戒め)。
2周半完走です!!ありやした!!!
ちょうど9月1日から始めて、今日が25日。なんとか目標としていた1ヶ月以内に終わりました。チュートリアルで学んだ内容はだいぶ頭に入ったと思いますが、つどつど疑問点を調べていると、まだまだ知らないこと99%あるんじゃないかって感じます。ゆえにまとめの最後の一文というわけです。というかまだスタートラインに立つためにアップしてるぐらいの感覚です。オレはようやくのぼりはじめたばかりだからな、このはてしなく遠い男坂をよ…
さて、 Railsチュートリアルについては一旦ここで終了です。次のステージはスクールに通うことです。ここまでやってきて、正直スクールうんぬんよりも、いかに自分で調べられるか、自走力・独学力が大事だなあと実感しました。が、記事タイトルどおり、自分には悠長なことを言っていられる時間はないのです。世の中に挑んでいくために、ぎゅっと集中して背水の陣で学習に臨む必要があるのです。
というわけで次の一手は、スクールを利用しての学習です。どっちにしろ自分で調べて考えてコードを書いていくことに変わりはないと思いますが、講師に自分のコードをみてもらい必要なことを教えてもらえるのはきっと価値があるし、時間短縮に繋がると考えています。金にモノをいわせる大人のやり方です。たいむいずまねーです。
とかグダグダ書いてるヒマがあったら勉強しろって話!それではまた!
記事書くのは好きなので、いつか有益な記事が書けるように精進します!!
⇦ 第13章はこちら
学習にあたっての前提・著者ステータスはこちら
####なんとなくイメージを掴む用語集
・Ajax
Asynchronous JavaScript + XML の略。ページを移動する・読み込み直すといったことをせずに、ページの内容をいろいろ動かしたりする技術。
・非同期
データを転送する際に、送信側と受信側のタイミングの一致(同期)を気にせずにデータをやり取りすること。
・XML(Extensible Markup Language)
拡張できるマークアップ言語。書き方のルールの一つ。主にデータのやりとりや管理を簡単にする目的で使われる。
・DOM(Document Object Model)
ホバリングしている黒いやつじゃないよ。プログラムからHTML等のWebページを自由に操作するための仕組みで、階層構造(ツリー構造)をとる。