Ruby
Rails
Railsチュートリアル

Ruby on Railsチュートリアルメモ

Rails5.0 第4版

演習の解答は抜けあり

第4章

Rubyのメソッドには暗黙の戻り値がある。
戻り値を明示的に指定しなかった場合、メソッド内で最後に評価された式の値が戻り値になる。

Rubyの配列はC++のvectorに似てると言えなくもない?(無理矢理な理解)

配列のインデックスには-1を使える。
配列の長さがわからなくても最後の要素を指定できる。

第5章

そういえば名前付きルートって変数だっけ?メソッドだっけ?
→メソッド(ヘルパーメソッド)

5.1

5.2

5.2.2

クラスのネストはそのまま内側に入れる
idのネストは親を&で参照する
という違い?

第6章

Userモデルの定義自体にはこのクラスがuserとかemailとかの属性を持っていることは示されていないが、じゃあどこのどいつがそれを定義しているのか?
db/schema.rb ?
マイグレーションしてschema.rbが更新されたタイミングでクラスがその属性を持つことが決まる?

モデルに属性を追加するにはマイグレーションファイルを作ってマイグレーションを実行してデータベースにカラムを追加する

第7章

7.1

7.1.2

id属性って何だっけ?と呆けた疑問が浮かぶ。
6章で既に説明されていた。

idというマイグレーションのときに説明されなかったカラムの存在に気づいたかもしれません。2.2で簡単に説明したとおり、このカラムは自動的に作成され、Railsが各行を一意に識別するために使います。

7.2

7.3

7.3.1

Usersコントローラのcreateアクションを作り始めた時点でnewアクションを見て、中で行っているUser.newは無駄なように思ったが、form_forの引数に使うから必要(7.2.1より)

form_forの引数で必要となるUserオブジェクトを作成することになります。

7.3.3

演習2

なぜURLは違っているのでしょうか?

  1. rootはstatic_pagesのhomeと決められている
  2. static_pages_controllerのアクションは空
    • home.html.erbがただ表示される
  3. サインアップボタンを押すと/signupに飛ばされる
    • これはhome.html.erbで決められている
  4. /signupにはUsersのnewアクションを対応させるとroutes.rbで決められている
  5. users_controllerのnewアクションでUsers.newされる
  6. new.html.erbが表示される
  7. 登録ボタンを押すと、users_controllerのcreateアクションに行くと思うが、それはどこで決めているかといえば、 form_forメソッドの結果として生成されたhtmlで、POSTで/usersに飛ぶと決めている
  8. routes.rbにresources :usersと書いたことで、POSTの/usersはusers_controllerのcreateと結びつけられている
    • resourcesってなんだっけ?
    • 説明 RESTfulなURLを自動生成
    • 使い方 resources :リソース名 [, オプション]
  9. createの失敗パターンでnew.html.erbが表示される

7.3.4

演習2
ユーザー登録フォーム送信後のURLが/signupになるように変更したが、users_signup_testの内容を変更していないのにGREENとなる。なぜか?という問い。
テストの中ではusers_pathに対してpostしている。そこをsignup_pathにしてもGREEN(これは当然か)
演習の中でPOSTの/signupをusers#createと結びつけたが、これを行ったからといって、resources :usersによる自動生成は無効化されないということか。
→この状態がいやなら、自分で潰さないとだめ。
onlyで自動生成の範囲を制限すればいける?

7.5.3

本番環境で最初のユーザー登録をしたらIDが2だった。
heroku run rails consoleでUser.firstを表示させると自分で登録したID=2のユーザーが表示された。
チュートリアルのスクリーンショットもよくみると/users/2になっている。
なんで最初のユーザーが2番?

第11章

11.3

11.3.1

演習1
トークンもダイジェストもnil

>> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: false, activation_digest: nil, activated: false, activated_at: nil>
>> user.activation_token
=> nil

演習2
このままauthenticated?を使ってもfalseになるだけ

まずemailが空なのを何とかする
いきなりremember_digestとかをattribute_updateしようとするとbefore_saveのdowncase_emailでnilに対してdowncase!しようとしてそんなことするメソッドはねーよと怒られる
そのあとダイジェストを更新(rememberで確認)

user.update_attribute(:email, "hoge@hoge.com") 
>> user.remember_token=User.new_token
=> "YvBNl3xjuzLJdusyY5lIbg"
>> user.update_attribute(:remember_digest, User.digest(user.remember_token))

>> user.authenticated?(:remember, user.remember_token)
=> true

11.3.2

演習1

rails routesの一部

edit_account_activation GET    /account_activations/:id/edit(.:format) account_activations#edit

:idの部分にトークンが含まれる

>> app.host
=> "www.example.com"
>> app.host="rails-tutorial-tkms0106.c9users.io"
=> "rails-tutorial-tkms0106.c9users.io"
>> app.host
=> "rails-tutorial-tkms0106.c9users.io"
>> app.root_url
=> "http://rails-tutorial-tkms0106.c9users.io/"
>> app.edit_account_activation_url(User.new_token, email: User.first.email)
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> "http://rails-tutorial-tkms0106.c9users.io/account_activations/8SCjpuNsnk0oPvQyXoeiaQ/edit?email=example%40railstutorial.org"

このURLを演習2で使っても有効化済なので「無効なリンク」とフラッシュメッセージが出るだけ。
コンソールから調べてみてください。という出題文を読み違えた?
rails consoleを使うってことじゃなくて、サーバーのログを見ろって意味?
まあ、おかげでapp.名前付きルートでURL確認できることがわかった。

演習2

気を取り直して開発環境で起動したアプリでユーザー登録してサーバーログから有効化URLを取り出す

<a href="https://rails-tutorial-tkms0106.c9users.io/account_activations/7BmIuAvmKxNwclKnEsTcdw/edit?email=hoge%40hoge.com">Activate</a>

URLに飛ぶとAccount activated!

rails consoleを開いてUser.last
activatedがtrueになっている

11.3.3

activate関連属性のupdateするコードをモデルに持っていくのは容易に理解可能だが、
有効化用のメールを送信するコードをモデルに入れるのはなんで?

演習1
データベース問い合わせを減らすためにupdate_columnsを使うように変えよう!という演習だが、なぜupdate_attributesではないのか?
少し調べた。

columnsは、attributesと違って、

  • バリデーション呼ばれない→updated,updated_atには必要ない
  • コールバック呼ばれない→使わない?
  • updated_atの更新しない→される必要はない。emailとか、ユーザーに見える属性が更新された時だけで良さそう

やることが少ないからcolumnsの方が速いのだろう。この演習の主旨にもcolumnsの方が合う。

演習2

@users = User.where(activated: true).paginate(page: params[:page])

redirect_to root_url and return unless @user.activated?

演習3
「ここまでの」って言うけど実際は演習2の変更に対してテストを書けという内容では?演習1はその中でテストGREENまで完結してるし…
現時点でfixtureにあるテスト用ユーザーは全部有効化済、有効じゃないユーザーを追加する必要がある

/usersに対する統合テスト
既にusers_index_test.rbがある。が、adminでログインしたときの一覧、non-adminでログインしたときの一覧、ページネーションとdeleteリンクについてのみテストしている。
有効なユーザーでログインして(管理者かどうかは今回どうでもいい)、有効じゃないユーザーは一覧に現れないことをテストする。

/users/:idに対する統合テスト
有効なユーザーでログインして、有効じゃないユーザーのページに直アクセスしようとしたらリダイレクトされることをテストする。
これ単体だとUsersコントローラの機能テストとして作ればいいじゃないかという気がするが、問題文は/usersと/users/:id両方に対する「1つの」統合テストを作成せよということなのかな?

11.4

本番環境でユーザー登録したあとログインするとユーザー自分一人
個別ページ開くとIDが101番
$ heroku run rails consoleUser.allしてみると100人ダミーがいる
なんじゃこりゃと思うが、前の章の最後に$ heroku run rails db:seedしてるから当然
有効化が存在しない時代のseedだから全員有効化されてなくて見えない

演習結果は確認できたから$ heroku pg:reset DATABASEで掃除(全消し)しておいた。
消した後、
$ heroku run rails db:migrate
$ heroku restart

第12章

12.1

routes.rbにresourcesで自動対応付けするとき、onlyで限定できるのにusersのときはなんで使わなかった?
/signupとusers#newを自分で紐付けたとき自動対応付けと被ってて、両方有効にならないように作ってテストもしたはずだが。
→7.3.4演習2か?
→記憶違いで、両方有効にならないように、は記憶違いで自動生成じゃない方のURLでないとREDになるようにテストを修正しただけだった。
ためしにdevelopment環境で起動して/users/newにアクセスしたらユーザー登録画面がしれっと表示された。

12.1.1

演習2

表 12.1の名前付きルートでは、_pathではなく_urlを使うように記してあります。なぜでしょうか? 考えてみましょう。

メールからジャンプできる形でないといけないからフルに表示される_urlを使う。
またこの表はリスト12.1に書いた行の結果使えるようになったもののすべてを表しているわけでなく、自動で対応付けされた組のうちこれを使うという表。別にpathが使えないというわけではない。

12.1.3

演習1

  1. この段階でフォームから有効なメールアドレスを送信すると、有効なのでfind_byでヒットする
  2. create_reset_digest呼ばれる
  3. validateもbeforeもないからupdate_attributeは何事もなく通過
  4. send_password_reset_email呼ばれる
  5. password_resetがselfを引数に呼ばれる
  6. password_resetは引数を取るように定義されていない(自動生成されてから手を加えてない)
  7. エラーになる

12.3.1

演習2

The action 'update' could not be found for PasswordResetsController
フォームの飛び先は/password_resets/
updateアクションを作るのは12.3.2だからこうなる

第13章

13.1.3

演習2

$ rails console --sandbox
Running via Spring preloader in process 1944
Loading development environment in sandbox (Rails 5.0.3)
Any modifications you make will be rolled back on exit
>> user=User.first
  User Load (0.4ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-10-28 03:21:46", updated_at: "2017-11-19 00:44:49", password_digest: "$2a$10$3.Pf2BCiwSJ8bodlZqpdXuSakl/No0nPlvwgFa8c9EB...", remember_digest: nil, admin: true, activation_digest: "$2a$10$0YG0DkvwVApnlDHldpx/S.aBEbcwG7FWee5GVHjh5hI...", activated: true, activated_at: "2017-10-28 03:21:45", reset_digest: "$2a$10$cGWvGK.xBDFlmCg88skhOeAImAZw3JUduGUuSm7wpQt...", reset_sent_at: "2017-11-19 00:44:49">
>> micropost = user.microposts.create(content: "Lorem ipsum")
   (0.1ms)  SAVEPOINT active_record_1
  SQL (1.4ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2017-11-29 13:32:41.608443"], ["updated_at", "2017-11-29 13:32:41.608443"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2017-11-29 13:32:41", updated_at: "2017-11-29 13:32:41">
>> user.microposts.find(micropost.id)
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ?  [["user_id", 1], ["id", 1], ["LIMIT", 1]]
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2017-11-29 13:32:41", updated_at: "2017-11-29 13:32:41">
>> user.microposts.find(micropost)
DEPRECATION WARNING: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`. (called from irb_binding at (irb):4)
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ?  [["user_id", 1], ["id", 1], ["LIMIT", 1]]
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2017-11-29 13:32:41", updated_at: "2017-11-29 13:32:41">

演習3

>> user == micropost.user
=> true
>> user.microposts.first == micropost
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> true

13.1.4

演習1

マイクロポストを2個作って実験
firstの方が新しい

irb(main):017:0> Micropost.first.created_at
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> Sat, 02 Dec 2017 11:24:52 UTC +00:00
irb(main):018:0> Micropost.last.created_at
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> Sat, 02 Dec 2017 11:24:27 UTC +00:00

演習2

firstはcreated_atのDESC(降順)で1行探す
lastはASC(昇順)

irb(main):019:0> Micropost.first
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 2, content: nil, user_id: nil, created_at: "2017-12-02 11:24:52", updated_at: "2017-12-02 11:24:52">
irb(main):020:0> Micropost.last
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 1, content: nil, user_id: nil, created_at: "2017-12-02 11:24:27", updated_at: "2017-12-02 11:24:27">

演習3

最初に投稿したマイクロポストのid

1

user.destroyMicropost.find_by_id(1)するとnil
→削除された

13.2

13.2.1

演習1、演習2

irb(main):002:0> helper.time_ago_in_words(3.weeks.ago)
=> "21 days"
irb(main):003:0> helper.time_ago_in_words(6.months.ago)
=> "6 months"
irb(main):004:0> helper.time_ago_in_words(1.year.ago)
=> "about 1 year"
irb(main):007:0> helper.time_ago_in_words(365.days.ago)
=> "about 1 year"
irb(main):008:0> helper.time_ago_in_words(364.days.ago)
=> "12 months"

演習3

irb(main):010:0> User.first.microposts.paginate(page: nil)
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ?  [["user_id", 1], ["LIMIT", 30], ["OFFSET", 0]]
=> #<ActiveRecord::AssociationRelation []>

注意を無視してpaginateを使わないと

irb(main):009:0> User.first.microposts.class
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> Micropost::ActiveRecord_Associations_CollectionProxy

13.2.2

演習1、演習2

irb(main):001:0> (1..10).to_a.take(6)
=> [1, 2, 3, 4, 5, 6]
irb(main):002:0> (1..10).take(6)
=> [1, 2, 3, 4, 5, 6]

演習3 大学

irb(main):003:0> Faker::University.name
=> "Southern New Hampshire University"
irb(main):004:0> Faker::University.name
=> "South Georgia University"
irb(main):005:0> Faker::University.name
=> "The Brown Institute"

13.2.3

演習1

コメントアウトは<!-- comment -->

13.3.1

演習1

DRYじゃないから

13.3.2

新しいマイクロポストをbuildする
current_user.microposts.build(micropost_params)

なにこれ?→newのエイリアス

13.3.3

マイクロポストの投稿が失敗すると、 Homeページは@feed_itemsインスタンス変数を期待しているため、現状では壊れてしまいます。

投稿が失敗=Micropostsコントローラのcreateメソッドで@micropost.saveがfalse
StaticPagesコントローラを通さずにhome.html.erbを描画する
→_feed.html.erbを描画する
@feed_items自体いないので、any?どころの騒ぎではなくなりエラー

13.3.4

演習1

DELETE FROM "microposts" WHERE "microposts"."id" = ?  [["id", 302]]

13.4.2

演習1

まずフロント側の警告が出る
「OK」を押してポップアップを消し、無視してそのままポスト
サーバー側でエラーPicture should be less than 5MB
しかしファイルはpublic/uploads/tmpの下にコピーされる(この時点で消えるわけではない)

演習2
Windowsで試した
「ファイルを選択」ボタンを押すとエクスプローラーが立ち上がる
チュートリアル内でビューに拡張子制限を入れたが、そのファイルだけが見えるようになっている
表示は「カスタム ファイル」となっている
image.png
ここを「すべてのファイル」にすると不適切なファイルも選択できてしまう
そのまま送るとサーバー側でエラーになるen.errors.messages.extension_whitelist_error

第14章

14.1

14.1.1

演習1
[2, 7, 10, 8]

演習2
[1]

14.1.2

演習1

irb(main):002:0> User.first.active_relationships.create!(followed_id: 2)
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (1.2ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", "2018-02-21 10:36:41.053391"], ["updated_at", "2018-02-21 10:36:41.053391"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2018-02-21 10:36:41", updated_at: "2018-02-21 10:36:41">

演習2

irb(main):006:0> User.first.active_relationships.first.follower
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  Relationship Load (0.2ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? ORDER BY "relationships"."id" ASC LIMIT ?  [["follower_id", 1], ["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2018-02-21 10:35:14", updated_at: "2018-02-21 10:35:14", password_digest: "$2a$10$noCibbKvW01tJk3.HnGaqubyf.zNRhVMqV4SWBNXF4/...", remember_digest: nil, admin: true, activation_digest: "$2a$10$2EfhkbiWsxeHDdeXZC/Xue1FO.cgBhR5JGMwBrwBFhi...", activated: true, activated_at: "2018-02-21 10:35:14", reset_digest: nil, reset_sent_at: nil>
irb(main):007:0> User.first.active_relationships.first.followed
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? ORDER BY "relationships"."id" ASC LIMIT ?  [["follower_id", 1], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
=> #<User id: 2, name: "Logan Nolan", email: "example-1@railstutorial.org", created_at: "2018-02-21 10:35:14", updated_at: "2018-02-21 10:35:14", password_digest: "$2a$10$tZukZEBFquCkr98iS75tj.obH0zrHKMmcYk/RvkPRdJ...", remember_digest: nil, admin: false, activation_digest: "$2a$10$4G4XI4QbNxAtXzuIeYpeT.tx2evOnS4STQDXsuIqmNv...", activated: true, activated_at: "2018-02-21 10:35:14", reset_digest: nil, reset_sent_at: nil>

14.1.3

疑問)followerとfollowedのIDが同じでもrelationshipは作れるが、大丈夫なのか?

演習

このバリデーションが必須でしたが、Rails 5から必須ではなくなりました。

???となったが…
必須でないということは、書かなくても強制されるということ(出典なし自己解釈)か。
確かに、関連付けられているのに、空でいいはずがない。

14.1.4

演習

User.first.following?(User.second)
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
  User Exists (0.1ms)  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.first.follow(User.second)
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
   (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.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (1.0ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", "2018-02-22 13:12:20.018805"], ["updated_at", "2018-02-22 13:12:20.018805"]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2018-02-22 13:12:20", updated_at: "2018-02-22 13:12:20">
User.first.following?(User.second)
  User Load (0.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
  User Exists (0.1ms)  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.first.unfollow(User.second)
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  User Load (0.0ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 1], ["followed_id", 2], ["LIMIT", 1]]
   (0.0ms)  SAVEPOINT active_record_1
  SQL (2.5ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 1]]
   (0.0ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2018-02-22 13:12:20", updated_at: "2018-02-22 13:12:20">
User.first.following?(User.second)
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
  User Exists (0.1ms)  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

14.2

14.2.2

リスト14.15に「Usersコントローラにfollowingアクションとfollowersアクションを追加する」と書いているが、正確にはアクションへのルーティングを追加しただけなのでアクションはまだない。
この時点で/users/4/followingへアクセスしても"The action 'following' could not be found for UsersController"となる。

14.2.6

演習1

format.html { redirect_to @user }をコメントアウトするとエラー

ERROR["test_should_unfollow_a_user_the_standard_way", Minitest::Result, 3.556019000003289]
 test_should_unfollow_a_user_the_standard_way#Minitest::Result (3.56s)
ActionController::UnknownFormat:         ActionController::UnknownFormat: ActionController::UnknownFormat
            app/controllers/relationships_controller.rb:16:in `destroy'
            test/integration/following_test.rb:45:in `block (2 levels) in <class:FollowingTest>'
            test/integration/following_test.rb:44:in `block in <class:FollowingTest>'

format.jsをコメントアウトすると成功のまま。