Railsチュートリアル 第2章 2.2 Usersリソース

2.2 Usersリソース

・2.1.1節で設定したユーザーのモデル設定と、それを表示するためのWebインターフェイスを組み合わせて「Usersリソース」を作る。
・これによって、ユーザーという概念をオブジェクトとして扱い、HTTPプロトコルに沿って作成/取得/更新/削除などの操作が行えるようになる。
・HTTPとは、"Hyper Text Transfer Protocol"の略で、Webサーバとクライアントが通信するときの手順を決めた規格のこと。簡単に言うと、ブラウザがサーバに送るリクエストの通信の規格みたいなもの?
・Usersリソースは、RoRの機能であるscaffoldジェネレータを使って作る。できたコードを理解する必要はない。
・scaffoldとは「足場」の意味で、家を建てるときに組む足場のこと。データの雛形を簡単に作成するコマンドみたいなもの?
・scaffoldコマンドを作るときには、以下のように、リソース名を指定し、属性(メンバ変数)の名前と型を指定しておく。なお、id:integerはデフォルトでついてくるので指定する必要はない。

$ rails generate scaffold User name:string email:string
Running via Spring preloader in process 4145
      invoke  active_record
      create    db/migrate/20200409173002_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      create      app/views/users/_user.json.jbuilder
      invoke  test_unit
      create    test/system/users_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss

・次に、データベースのマイグレートという作業をする必要がある。今、確かにUsersリソースの雛形はできたが、実際にユーザーに登録してもらった内容はデータベースとしてSQLなどで管理する必要があり、このままでは使えない。リソースからデータベースを自動で作ってくれる機能がマイグレーションで、作ったモデルをデータベースの形になおしてくれる。
www.transnet.ne.jp

$ rails db:migrate
== 20200409173002 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0015s
== 20200409173002 CreateUsers: migrated (0.0020s) =============================
2.2.1 ユーザーページを探検する

・ここまでやると、プレビューでUserの登録/表示/編集/削除ができるようになる。例のごとくプレビューをブラウザの方で開くと未だ"hello, world!"と表示されるが、そのURLに/usersをつけてみると全ユーザーを表示するページが開ける。/usersが全ユーザーの表示 index、/users/1がid:1のユーザーの表示 show、/users/1/editがid:1のユーザーの編集の edit,/users/newが新規ユーザーの作成 newというアクションにそれぞれ対応している。

・演習
Q1.User was successfully createdの文章のCSSはどうなっている?リロードするとどうなる?
A1.

User was successfully created.

から

に変化した。つまり、動的にページが作成されている。

Q2.email欄を空白にしてユーザーを作るとどうなる?
A2.Emailに値を持たないUserが作られる。

Q3.正しくないEmailを入力するとどうなる?
A3.そのまま登録される。つまり、ユーザー名の重複、不正なアドレス、Name/Emailのヌケをチェックする機能をつけなければならない。

Q4.上記のユーザーを削除するとなんと言われる?
A4.User was successfully destroyed.

2.2.2 MVCの挙動

・ここまで、scaffoldジェネレータによってUsersリソースが作成されていることは確認できた。実際これがどのように動いているのかを、MVCの挙動を見て理解する。
 ①ブラウザが/usersというURLのリクエストをRailsサーバーに送る。(ブラウザ→routes.rb)
 ②routerがリクエストを受け取り、routerによってControllerのindexアクションに割り当てられる。(routes.rb→users_controller.rb)
 ③indexアクションが実行され、Users Modelに「すべてのユーザーを取り出せ」と指令がいく。(users_controller.rb→users.rb)
 ④Users Modelが問い合わせを受け、すべてのユーザーをデータベースから取り出す。(users.rb→データベース→users.rb)
 ⑤ユーザーのデータがUsers ModelからUsers Controllerに渡される。(users.rb→users_controller.rb)
 ⑥Users Controllerがデータを@users変数(インスタンス変数)に保存し、index Viewに渡す。(users_controller.rb→index.html.erb)
 ⑦index Viewが起動し、Embed Ruby:ERBに沿ってページをレンダリングして、Users Controllerに返す。(index.html.erb→users_controller.rb)
 ⑧Users Controllerがページをブラウザに渡す。(users_controller.rb→ブラウザ)

・ルートのページを、hello,からindexに変えたい。そのためにはroutes.rbを以下のように編集すればよい。

Rails.application.routes.draw do
  resources :users
  root "users#index"  
end

・users_controller.rbにある各メソッドは、RESTアーキテクチャというrubyの設計思想を構成する全アクションである。RESTとは"REpresentational State Transfer"の略であり、Webアプリケーションを構成するコンポーネントを「リソース」として扱うというもの。リソースは標準でCreate/Read/Update/Delete(CRUD)の4つのアクションと、POST/GET/PATCH/DELETEの基本的な4つのHTTPリクエストに対応している。要はオブジェクト指向で全オブジェクトがもともと4つのアクションを持っている感じ?

HTTPリクエスト	URL	アクション	用途
GET	/users	index	すべてのユーザーを一覧するページ
GET	/users/1	show	id=1のユーザーを表示するページ
GET	/users/new	new	新規ユーザーを作成するページ
POST	/users	create	ユーザーを作成するアクション
GET	/users/1/edit	edit	id=1のユーザーを編集するページ
PATCH	/users/1	update	id=1のユーザーを更新するアクション
DELETE	/users/1	destroy	id=1のユーザーを削除するアクション

・演習
Q1.user/1/editのリクエストが送られたときの処理の図は?
A1.f:id:mockingum:20200415142938p:plain

Q2.どのコードがユーザーデータを取得している?
A2.順番に見ていく。まず、Controllerのusers_controller.rbのeditメソッドには何も書かれていない。(これでどうやってmodelに命令だしてるの?)次に、Modelのuser.rbも、ApplicationRecordクラスをそのまま継承したUserクラスがあるだけなので、editはApplicationRecordクラスにあるメソッドだと思う。最後にViewのedit.html.erbを見ると、以下のようになっている。

<h1>Editing User</h1>

<%= render 'form', user: @user %>

<%= link_to 'Show', @user %> |
<%= link_to 'Back', users_path %>

これを見ると、editのページでは、formページをレンダリングし、ShowとBackの2つのリンクを作ることになっている。formに対し引数として?userインスタンスを@userで渡している。そこでformを作ってそうな、_form.html.erbを見てみる。

<%= form_with(model: user, local: true) do |form| %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name, id: :user_name %>
  </div>

  <div class="field">
    <%= form.label :email %>
    <%= form.text_field :email, id: :user_email %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

上半分はエラー処理なので、下半分がフォームの本体。渡された@userのnameとemailを表示している。ここまでの作業で、ユーザーのデータを取得しているのはControllerで、その時の命令は、indexのときと違い「id:1のユーザーを取得しろ」となっているはずである。しかしeditメソッドには何も書かれていない。このことから、UsersControllerの親クラスであるApplicationControllerのeditメソッドが、デフォルトで「id:nのユーザーデータを指定しろ」となっているはずである。

Q3.ユーザーの情報を編集するページのファイル名は?
A3.上記のように、edit.html.erb。

2.2.3 Usersリソースの欠点

・このようにscaffoldジェネレータは簡単にモデルを作成できるが、このままでは以下のような問題がある。
 ・エラー処理がない(名前やメアドを空欄にした場合など)
 ・ユーザー認証がない(IDとパスワードでログインしないで、誰でも他のユーザーの情報をいじれてしまう)
 ・テストが書かれていない?(テストとは?)
 ・デザインに一貫性がない。
 ・コードが読みづらい。