kuma0319のブログ

webエンジニアになるためのアウトプットブログ

Ruby on Railsチュートリアル第2章

Railsチュートリアルの第2章を進めていきます。

第2章(Toyアプリケーション)

第2章はscaffoldジェネレータで簡単なアプリを作成し、railsのおおまかな機能を学習するといった感じです。

序盤のrails newgit pushの内容は第1章と重複するので特に書きません。

UserモデルとMicropostモデル

ここでは、まずtoy_app用のモデル設計を考える。
個々のユーザーを表すUserモデルと、投稿するMicropostモデルの2つを扱う。

ユーザーモデルの設計

ここではユーザー(users)のデータベースが持つ情報はid、name、emailの3つのみ。

カラム名 データ型
id integer
name string
email string
マイクロポストモデルの設計

マイクロポスト(micrioists)のデータベースが持つ情報はid、content、user_idの3つ。contentはstring型だと255文字が限度なため、textが好ましい。
このuser_idはusersと関連付け(belongs_to)のために必要。

カラム名 データ型
id integer
content text
user_id integer

scaffoldジェネレータ

Railsにおけるscaffoldコマンドの機能は、アプリケーションの基本的な機能を一括生成してくれるコマンド。

rails g scaffoldを実行します。※モデルの命名規則は"単数形"のため、Userとする。
DBのマイグレーションも実行しておく。

$ rails g scaffold User name:string email:string
 $ rails db:migrate

最初scaffoldコマンドを使用した際は、これがどれだけ便利なのかはよく分かりませんでしたが、14章まで進めて一度実装を終えると、scaffoldの手軽さが実感出来ます。

Usersリソース

ここではscaffoldで既にほとんど記述されているので、MVCの動きを押さえておきます。

ルーティング

ルーティングのrootURLをusersコントローラのindexアクションへ紐づけられる。

[config/routes.rb]
Rails.application.routes.draw do
  resources :users
  root 'users#index'
end
コントローラ

usersコントローラのindexアクションは、User.allを@usersへ代入するメソッド。

[app/controllers/users_controller.rb]
class UsersController < ApplicationController
  .
  .
  .
  def index
    @users = User.all
  end
  .
  .
  .
end
モデル

Userクラスについても以下のようにモデルで定義し、ApplicationRecordを継承しているためindexアクションのUser.allに対してDB上のユーザーを取り出すことが可能。

[app/models/user.rb]
class User < ApplicationRecord
end
ビュー

コントローラのindexアクションに対応するビューのindex.html.erbをrailsが探し、HTMLとしてブラウザに表示する。
ここでは、@usersに代入されたユーザー一覧を一人ずつ出力(_userパーシャルでnameとemailを表示する内容が記述)する。

[app/views/users/index.html.erb]
<p style="color: green"><%= notice %></p>

<h1>Users</h1>

<div id="users">
  <% @users.each do |user| %>
    <%= render user %>
    <p>
      <%= link_to "Show this user", user %>
    </p>
  <% end %>
</div>

<%= link_to "New user", new_user_path %>

Micropstリソース

マイクロポストの生成

Micropostモデルについてもrails g scaffoldを実行。※モデルの命名規則は"単数形"のため、Micropostとする。
マイグレーションも実行。

$ rails generate scaffold Micropost content:text user_id:integer
$ rails db:migrate
マイクロポストのバリデーション

マイクロポストのコンテントのバリデーションに140文字制限を追加する。

[app/models/micropost.rb]
class Micropost < ApplicationRecord
  validates :content, length: { maximum: 140}
end

ここの記述はハッシュやシンボルが普通に出てきているので理解を定着させるために考えておく。
validates :content, length: { maximum: 140}のうち、:contentはシンボル。length: { maximum: 140}はネストされたハッシュであり、:length => { :maximum => 140 }のようにも記述できる。{ }内の:maximumはキーで140がバリュー。更に:lengthキーに対して{ :maximum => 140 }がバリューとしてネストされている。

ユーザーとマイクロポストの関連付け

後半でも出てくるが、ユーザーとマイクロポストの関連付けをおこなう。
1人のユーザーは複数のマイクロポストを持つ(has_many)ことができ、マイクロポストは必ずユーザーに属している(belongs_to)。これをユーザーモデルとマイクロポストモデルに記述しておく。

[app/models/user.rb]
class User < ApplicationRecord
  has_many :microposts
end

[app/models/micropost.rb]
class Micropost < ApplicationRecord
  belongs_to :user
  validates :content, length: { maximum: 140 }
end

コンソール操作は飛ばします。

継承

継承について軽くまとめておきます。
ユーザーモデルやマイクロポストモデルは、"ApplicationRecord"クラスを継承している。"ApplicationRecord"クラスは更に"ActiveRecord: :Base"を継承しており、階層下のモデルはRubyの属性のように扱えデータベース操作が可能になる。 コントローラも"ApplicationController"を継承しており、更に"ActionController::Base"を継承している。階層化のコントローラは、モデルオブジェクトの操作や、送られてくるHTTP requestのフィルタリング、ビューをHTMLとして出力するなどの多彩な機能を実行できる。

REST

REST(REpresentational State Transfer)についてチュートリアル内では原則的なものについて詳細は記載されていなかったのでまとめておきます。
ただ、媒体によっては4つであったり6つであったり、若干表現が違っていたりしました。
私は以下の書籍を参考にしました。

イラスト図解式 この一冊で全部わかるWeb技術の基本 | 小林 恭平, 坂本 陽, 佐々木 拓郎 | コンピュータ・IT | Kindleストア | Amazon

また、補足的に図もついてまとめられていた以下のサイトも参考としています。

REST APIとは?ざっくりと理解してみる【初心者向け】 - Wiz テックブログ

1. 統一インターフェース

あらかじめ定義、共有化された方法で情報がやりとりされる。HTTPプロトコルのメソッドであれば、GET、POST、PUT、DELETEという4つ。

2. アドレス可読性

すべての情報が一意なURIで構成されている。

3. 接続性

やり取りの情報にはリンクを含めることが出来る。

4. ステートレス性

やりとりは独立しており、前回のリクエスト/レスポンスの影響を受けない。各リクエスト内で必要な情報(ユーザーID、アクセストークンなど)を保持する。

RESTとCRUDの関係

また、Raisチュートリアル内では、RESTにおけるHTTPリクエストとリレーショナルデータベース(RDB)とが対応していると記載がありました。
最初はよく分からなかったのですが、RESTとCRUDについてまとめられていたサイト(https://www.logicmonitor.jp/blog/rest-vs-crud)を参考にして自分なりに解釈しました。
RESTにおけるHTTPメソッドはHTTPリクエストを介したデータ操作であり、CRUDはリレーショナルデータベース操作であり、対応はしているが本質的には異なる。例えば、CRUDのUpdateはRDBのリソースの一部を更新するが、PATCHはより広義的な操作でリソース全体の更新も可能。おそらくCRUDの方がより限定的な機能と言える。

REST CRUD
POST Create
GET Read
PATCH Update
DELETE Delete

第2章ー演習ー

2.2.1

①emailを入力せず、名前だけを入力しようとした場合、どうなるでしょうか?
(解答) emailが空でもユーザーは作成出来てしまう。

②「@example.com」のような間違ったメールアドレスを入力して更新しようとした場合、どうなるでしょうか?
(解答) これもユーザーは作成出来てしまう。

③上記の演習で作成したユーザーを削除してみてください。ユーザーを削除したとき、Railsはどんなメッセージを表示するでしょうか?
(解答)User was successfully destroyed. というフラッシュメッセージが表示される。

2.2.2

①図 2.12を参考にしながら、/users/1/editというURLにアクセスしたときの振る舞いについて図を書いてみてください。
(解答) 図は省略。流れとしては、(1)/users/1/editにアクセス(GET)する → (2)resources :usersルーティングによってeditアクションへ振り分けられる → (3) editアクションはbefore_actionでset_userメソッドが定義されており、@user変数にはUser.findのuserが代入される。→ (4)editに対応するビュー(index.html.erb)において@userの編集ページが表示される。

②図示した振る舞いを見ながら、Scaffoldで生成されたコードの中でデータベースからユーザー情報を取得しているコードを探してみてください。(ヒント: set_userという特殊な場所の中にあります。)
(解答)①の(3)部分に該当。

③ユーザーの情報を編集するページのファイル名は何でしょうか?
(解答) [app/views/users/edit.html.erb]

2.3.1

①マイクロポストの作成画面で、ContentもUserも空のまま作成してみるとと、どうなるでしょうか?
(解答)両方空でも作成出来てしまう。

②141文字以上の文字列をContentに入力した状態で、マイクロポストを作成しようとするとどうなるでしょうか?(ヒント: WikipediaRubyの記事にある設計思想の引用文が140文字を超えているので、これをコピペしてみましょう。)
(解答)これも作成出来てしまう。

③上記の演習で作成したマイクロポストを削除してみましょう。
(解答)Micropost was successfully destroyed.のフラッシュメッセージと共に削除出来た。

2.3.2

①先ほど2.3.1.1の演習でやったように、もう一度Contentに141文字以上を入力してみましょう。どのように振る舞いが変わったでしょうか?
(解答)「Content is too long (maximum is 140 characters)」のバリデーションエラー。

2.3.3

①ユーザーのshowページを編集し、ユーザーの最初のマイクロポストを表示してみましょう。同ファイル内の他のコードから文法を推測してみてください(コラム 1.2で紹介した技術の出番です)。うまく表示できたかどうか、/users/1にアクセスして確認してみましょう。
(解答) ユーザーのshowページに<%= render @user.microposts %>を追加すると、/users/1に表示されるようになる。

②リスト 2.18は、マイクロポストのContentが存在しているかどうかを検証するバリデーションです。マイクロポストが空でないことを検証できているかどうか、実際に試してみましょう(図 2.18のようになっていると成功です)。
(解答)「Content can't be blank」のバリデーションエラーが発生。

③リスト 2.19の(コードを書き込む)となっている箇所を書き換えて、Userモデルのnameとemailが存在していることを検証してみてください(図 2.19)。
(解答)以下のバリデーションを加えて、空のユーザーを作成すると、「Name can't be blankとEmail can't be blank」が発生。

[app/models/user.rb]
class User < ApplicationRecord
  has_many :microposts
  validates :name, presence: true
  validates :email, presence: true
end

2.3.4

①Applicationコントローラのファイルを開き、ApplicationControllerがActionController::Baseを継承している部分のコードを探してみてください。
(解答) 以下の部分

[app/controllers/application_contoroller.rb]
class ApplicationController < ActionController::Base
end

②ApplicationRecordがActiveRecord::Baseを継承しているコードはどこにあるでしょうか? 先ほどの演習を参考に、探してみてください。(ヒント: コントローラと本質的には同じ仕組みなので、app/modelsディレクトリ内にあるファイルを調べてみましょう。)
(解答) 以下の部分

[app/models/application_record.rb]
class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class
end

第2章ーまとめー

  • scaffoldジェネレータでindex、new、showといった多くのアクションとそれに対応するモデルとビューが自動生成される。
  • scaffoldそのままだと、バリデーションやモデルの関連付けは全くおこなわれていない。
  • RailsMVCモデルによってブラウザからのリクエストからレスポンスまでの流れが決まっている。
  • データモデルの関連付けに、has_manybelongs_toが活用される。
  • RESTという設計は4原則で成り立っており、RESTに従って構成されたものをRESTfulと呼ぶ。
  • RESTのHTTPリクエストメソッドとリレーショナルデータベースのCRUD操作には相関があるが、全く同一のものでは無い。

実際にアプリ作る際はscaffoldなどなるべく工数かからないものをがんがん取り入れていこうと思います。そのための下地としてRailsチュートリアルをちゃんと理解しておきます。
第2章終わり🐻