プログラミング年少組のど素人が、アウトプット用に素人目線の解説を書いていきます。
自分が自分に教えていることを想像しながら進めていきます。
下記と同じような境遇の方であれば参考になるかも
- まっさらなプログラミング初学者目線
- オール独学
- 勉強は得意じゃない
- 社会人のため、1日に勉強できる量は限られる。
電子書籍のwebテキスト(第6版)を購入して使用
Progateの「Web開発パス」完走済
ドットインストールのプレミアム会員卒業
Railsチュートリアル解説動画を見ながら学習中
7章#
Userモデルの作成でユーザー登録における裏側(見た目ではわからない部分)動きを作ってきました。
対して7章ではサイトのユーザー登録における表側、つまりは見た目を整えていきます。
要はユーザー登録ページを作成するということになります。最終的にはプロフィール表示までやっていきます。
難易度も徐々に上がっていくみたいですので心してかかりましょう!オス!
7.1 ユーザーを表示する#
まずはユーザーの「名前」「プロフィール写真」を表示するためのページを作成するみたいです・・・ついさっきプロフィール表示は最後と言ってたけども・・・
まずは章の始めなのでいつものようにブランチから作成しましよう
$ git checkout -b sign-up
7.1.1 デバッグとRails環境##
ここでは各ページのレイアウトに「デバッグ情報」なるものを追加します。(コードでおかしなところを表示させることかな・・・)
**「debugメソッド」と「params変数」**を使ってそれを実現していきます。
初めて出る単語だらけですが、詳しいことは後ほど説明されるみたいです
とりあえずテキストの通りにフッターの下に以下のコードを入れてみましょう
<%= debug(params) if Rails.env.development? %>
追加するのはこの1行でいいみたいですが、何のことやらサッパリーです
とりあえず解読していきましょう
まずは**「if Rails.env.development?」**についてです
Railsは「Railsの状況が・・・」的なニュアンスでしょうか
envは「environment」が短くなっているっぽいので「環境」を指していて
developmentは「開発環境」のこと
さらにさらに
ifは「もし・・・」
<%= %>は表示(出力)させるタイプの埋め込みRuby
つなげてみると・・・「もし、Railsの環境が開発環境ならば、debug(params)情報を表示させる」
なんとなく見えてきました。
ここでさりげなくあります「環境」についてですが、他にも「本番環境」「テスト環境」などがあります。
コードのおかしなところについて表示させるのは「開発環境」のみにしようという意図でしょうね
コラムを飛ばしていくと見た目を整えるCSSが載ってるんでコピペしときましょう
ここでSassのミックスイン機能が使われています
5章でチラッと出てきましたが、CSSの繰り返し使いそうなデザインをパッケージ化して埋め込むことができます
@mixin box_sizing {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
このように変数っぽい使われ方がされています
使いたい時は「box_sizing」を呼び出せばいいだけです
呼び出す時はこのように「@include
」の後に付け加えれば良いだけです
@include box_sizing; # ;(セミコロン)を忘れずに!
これで一応デバッグ情報が各ページに表示される状態になりました。一応「rails server」で確認しときましょう
コラム7.1 Railsの3つの環境##
「development(開発環境)」なんてものが出てきましたので、ここでは少しそれを掘り下げています
Railsには環境というカテゴリーで分けると3つに分類されます
①テスト環境(test)
②開発環境(development)
③本番環境(production)
それぞれのカテゴリーが何を表しているのかは名前を見れば何となく想像はつきそうです。
例えばテキストを見ながらコードを書いているのは開発環境だったり、Herokuでデプロイした後にURL検索したら出てくるページが本番環境だったりする感じですかな。
テスト環境って・・・これはよくわかりませんね。テストしてるんでしょうね。
今どこの環境にいるかは「rails console」を開いて、「Rails.env」と入れれば教えてくれるみたいです
>> Rails.env
=> "development"
試してみると。こんな風に出力されました。どうやら今は開発環境下にいるみたいです。
むしろデフォルトでそうなっているみたいです
「rails console」はデフォルト環境
「rails console」でテスト環境下に入ることもできます
$ rails console test
と、「test」と加えるだけです。やってみたけど、できませんでした・・・なんでだろ
今度は「rails console」ではなくて「rails server」ではどうかをみていきましょう。
「rails server」はテスト環境ではなくて本番環境の実行方法をみています
$ rails server --environment production
今度は「rails console test」のようにただ単語をくっつけるのではなくて「--environment」と前置きが必要になっています。そしてこれだけでは動きません。
本番環境で使用する際は、本番用のデータベースが必要になってきます
データベースへの指示はおなじみの「rails db:migrate」で行います
もちろんいつものカラム追加などの指示とは一味違うためおまけがついています
$ rails db:migrate RAILS_ENV=production
このように、直近で使うことがなさそうなので紹介程度に書かれていました。
それぞれの環境への変更方法が、「rails console」と「rails server」と「rails db:migrate」で違うことだけ頭の片隅に入れておきましょう
以上。内容のうっす〜〜いコラムでした
7.1.2 Usersリソース##
ここは、これまでのおさらい的な色が濃いです。。
まずはデータベース上に登録されているユーザーがいなければ、登録されている状況を作りましょう
まだ、登録用のフォーマットがないため「rails console」から作成します
>> User.create(name: "hogehoge", email= "hogehoge@hoge.hoge, password: "foobar", password_confirmation: "foobar")
「User.create」で「作成」と「保存」を同時にやっております。
とりあえずこれで「idが 1 」のユーザーが一人登録されましたので、今度はそのユーザーが画面表示されるようにしましょう。
ここで補足ですが、「rails console」で作ったデータは最終的に消した方がベターです。
てか消しましょう。
なぜなら、現実的にサイトの運用を開始したあとは「rails console」でユーザー登録するケースなどないからです。むしろデータベース上に「rails console」で登録された情報が残っているここと自体あまりよろしくありません。。
前置き長くてすみません。これが消すためのコードです(あとでまた出てきます!)
$ rails db:migrate:reset
RESTの概念を使う
ユーザーの情報が表示されてるページっていわゆるプロフィールページに当たりますが、そこを検索するためのURLについてはすでに2章で学習済みです。
テキストにある通り、RESTの概念を使うと、それぞれの用途に応じたURLやアクションがすでに割り当てられています
その表がこちら・・・としたいのですが、めんどくさいので該当部分だけ抽出すると
今回の用途
id = 1 のユーザーを表示するページを出したい
利用するアクション名
show
URL
/users/1
HTTPリクエスト
GET
なので「GET」リクエストで「show」アクションを使って「/users/1」にアクセスすると良さそうです。
さっそく「rails server」を開いて、URLのお尻に「/users/1」をひっつけてエンターしてみると
エラーです!そりゃそうです。当たり前ジャン!
「show」アクションに対する①ルーティングも②ビューも③コントローラーも何もかもまだ作成してないから当然です!!
① それではまずはルーティングからボチボチやっていきましょう
とは言っても、ここでも2章でやったRESTの概念を利用します
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
resources :users # これを追加
end
「resources :users」これを1行バーーンと入れるだけでRailsで基本となる7つのアクションへのルーティングが定義されます
7つのアクション:index,show,new,cerate,edit,update,destroy
しかもこれ、5章でやった「名前付きルート」にも対応しているということです・・・便利すぎるな
ちなみに今回のように、「特定のユーザーを表示するページ」の名前付きルートは「user_path(user)」ということになっとります。そのうち使うことになるかもね。
② ルーティングが完成しましたので、次はビューにしますか
忘れてましたが、5章の終わりらへんでusersコントローラーは以下のコマンドで作成しました
$ rails generate controller Users new
ですので、usersコントローラーに対応するアクションは「new」のみ作成されており、今回必要となる「show」アクションやビューに関することは全く手付かずの状態です。
アクションやビューだけを作るコマンドはないので手動で作成しましょう
ビューのところに「show.html.erb」ファイルを作成します
ここ👉 app > views > usersの中
ファイルを作ったら、開いてとりあえず内容を入れときましょう
<%= @user.name %>, <%= @user.email %>
③最後にコントローラーでshowアクションを定義します
現段階でビューではまだ@user
って何?という状態になってます。
showアクションで「@user
ってこれのことよ!」としてあげればビューで使えるようになりそうです
def show
@user = User.find(params[:id])
end
@user
とは!・・・idが 1 のユーザーのことだお!
と言ってるみたいです。これはparams[:id]の部分がユーザーidの1に置き換わっているためです。
「paramsの中のidが1になって、idが1のfindをかける」という流れになっているみたいです
(paramsとはURLのお尻についているそれぞれのユーザーが持っているidのこと?)
ローカル変数「user」とインスタンス変数「@user
」について
ちなみに@をつけたインスタンス変数にせずに単に変数「user」には入れられないの?
user = User.find(params[:id]) # これだとuserアクションのみでしか変数userは使えない
これだと、userコントローラーでしか使えないので、ビューファイルで「user」を入れても動かないのです
ですので、ビューファイルでも使えるようにするにはインスタンス変数@user
にする必要があるのです
7.1.3 debuggerメソッド##
「debugger」メソッドを使うことによって、よくわからない挙動がおきた場合に原因を調査することができます。
①挙動がおかしい原因として、怪しいとされるコードの部分付近に「debugger」を差し込む
def show
@user = User.find(params[:id])
debugger # こんな風に「debugger」といれるだけ
end
②サーバーを開いてターミナルの中身を確認する
これだけで、debuggerが呼び出された瞬間の状態を確認することができるワケです
要するに、そこで処理を止めて今どういう状況にあるかをターミナルで確認できます。
エラーが見つかって、バグが取り除けない状況に陥った時はこれを使います
チュートリアルでは今後登場することはないみたいですが・・・
7.1.4 Gravatar画像とサイドバー##
プロフィール画面にプロフィール写真を載せられるようにしましょう
そのために、ここではGravatarという画像を扱う際にはとっても便利なサービスを使います
Gravatorとは
Gravatarは無料のサービスで、プロフィール写真をアップロードして、指定したメールアドレスと関連付けることができます
Gravatarに画像を登録すると、メールアドレスと紐付けられます。あとは画像を載せたい部分にgravatar_forメソッドの中でそのメールアドレスを入力すればGravatarに登録した画像が表示されるという仕組みです。
余計ややこしくなったかな・・・
さてさて、その便利なサービスを使えるようにするには準備が必要です
①ビューファイルでGravatar画像を使うには「gravatar_for」ヘルパーメソッドを使います
<% provide(:title, @user.name) %>
<h1>
<%= gravatar_for @user %> # ここに「Grabatar」画像が表示される
<%= @user.name %>
</h1>
とは言え、「gravatar_for」ヘルパーメソッドなんてまだ定義もしてないので使えません。。
なので定義しましょう
②「gravatar_for」ヘルパーメソッドを定義します
ヘルパーメソッドとか久しぶりに出てきましたが、すべてのビューで利用できるとういう特徴がありました。
今回はUsersコントローラに関連付けられているヘルパーファイル「users_helper.rb」で定義していきましょう。(なぜなら「gravatar_for」メソッドはuserでしか使わないだろうから・・)
ここ👉 app > helpersの中にある
ファイルを開いたらコードをコピペして眺めましょう
module UsersHelper
# 引数で与えられたユーザーのGravatar画像を返す
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
これをヘルパーファイルに入れれば「gravatar_for」が使えるようになります
とりあえず、準備が整いましたので「gravatar_for」が使えます
「rails server」を更新して見ましょう。いい感じに画像が表示されたかと思います。
最後にビューでレイアウトを整えていきましょう
レイアウトに関することなので、ここでも「Bootstrap」が登場します
<% provide(:title, @user.name) %>
<div class="row"> # Bootstrapのクラス
<aside class="col-md-4"> # Bootstrapのクラス
<section class="user_info">
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>
</aside>
</div>
「Bootstrap」も覚え出したらキリがないのでコピペに留めときます
そしてcustom.scssファイルでCSSを整えたら、それらしきものが出来上がります。。
7.2 ユーザー登録フォーム#
順番が前後しましたが、今度はユーザー登録フォームを作ります。
(最初に登録フォーム作って、最終的にプロフィール作るって言ってたから・・・)
いわゆる**「新規登録」**に当たる部分です
これから作るみたいな感じでゆーてますけども、実はもうできてるんです
ルーティングもビューもあります。
トップページの真ん中にデカデカとある「Sign up now!」がそれに該当します!
まあ・・開いたところで、いかにも「仮で作りました」感満載のページが出てきますけども・・・
これからそれを作っていくんです!!
7.2.1 form_withを使用する##
ここでは超重要なform_withメソッドが登場します
これはヘルパーメソッドで、ActiveRecordのオブジェクトを取り込み、そのオブジェクトの属性を使ってフォーム構築しますとか訳のわからないことが書かれています。
そもそもフォームフォームっていきなり出てきたけど何なんでしょうか
これまではデータベースにデータを入れるためには、「rails console」を使ってきました
が、ユーザーがサイトに新規登録するのに
ええ〜っと、まずはターミナルから「rails console」を開いて・・・
なんてする訳がありません。やったこともありません
当然、新規登録用のページの登録「フォーム」に名前やemailアドレス、パスワードなんかを入れていたと思います
ついついフォームと言っちゃいましたが、あの入力するボックス。そこに何個もあるのが入力フォームであり、そこに入れた値が、エンター押すとデータベースに飛んでる流れです。
これはブラウザからデータベースにデータを送信して保存するという今までになかった新しいパターンです
ですので、これから、その、入力フォームに値を入れて、エンターして、データベースに保存されるまでの流れを見ていく感じです。
まずは、その流れというものを見ていきましょう
ビューで使われる「form_with」では@user
変数を使います
まずは、その@user
がなんなのかをnewアクションで定義します
def new
@user = User.new
end
Userをnewしたやつを入れてるんですね。ふむふむ
これはcreateじゃないから、後でsaveすることでやっとデータベースに入って・・・という流れが見えてきそうです
「GETアクションが/users/newにきた時にnewアクションが反応します」
とりあえずここでいったん話を切り替えて、ビューのレイアウトを整えていきます
テキストコピペして見てみると・・・見違えるように、それらしいページに生まれ変わるじゃありませんか
7.2.2 フォームHTML##
さてさて、いつもならレイアウトの部分はテキストコピペして完成したのを見て、わあすごーい。で、終わっていましたが、今回はそうはいきません
なぜなら・・・「form_with」が入ってるから・・・
それではビューのコードを紐解いていきましょう
<%= form_with(model: @user, local: true) do |f| %>
.
.
.
<% end %>
まずはなんか見覚えのある形、|f|を見ると思い出しますね。この形は「ブロック変数」でありました。
よく見ると、「form_with」に( )で引数がついてて、「do」とあります
下に目を移すと「end」があるので間違いありません
これは「do」から「end」までが「ブロック」です
<%= form_with 〜 | f | %> 以下がフォーム部分を表しています。ここの部分はHTMLで表現すると別の形になるのですが、デベロッパーツールなんかで見ることがきます。
ちなみに1行目の<%= form_with 〜 | f | %>
全部バラしたものがテキストに載ってます。
<form accept-charset="UTF-8" action="/users" class="new_user"
id="new_user" method="post">
重要なのは「action="/users"」と「method="post"」で、"/users"に"post(送信)"するよ〜を意味しています。きっと以下に書かれている内容を"/users"に送信しますよ〜〜を表しているのでしょう
<%= f.label :name %>
<%= f.text_field :name %>
ナンジャコリャ〜〜〜ですが、
ポイントは**「 f 」**です。
テキストにはHTMLフォーム要素(テキストフィールド、ラジオボタン、パスワードフィールドなど)に対応するメソッドが呼び出されると、@user
の属性を設定するために特別に設計されたHTMLを返しますと、あります。
入力する項目には様々なものがありますよね。
・テキストフィールド(名前などの文字を入力するところ)
・チェックボックス(該当するものにチェックするところ(複数選べるタイプ))
・ラジオボタン(該当するものにチェックするところ(一つだけ選ぶタイプ))
・送信ボタン(一通り入力し終わったら押すボタン)
・他にも「数値」とか「日付」など・・・
これらがHTMLフォーム要素であり、これに対応するメソッドを「 f 」にくっつけることによって、HTMLを作ってくれます。
もう一度コードを見てみましょう
<%= f.label :name %>
<%= f.text_field :name %>
「 f 」に引っ付いてる「label」やら「text_field」はまさに「HTMLフォーム要素に対応するメソッド」です
(「label」はここは何を入力するところ!示すためのフォームの「タイトル」を表す)
じゃあ「name」ってなんでしょうか
ここで入力するフォームって最終的にはデータベースに保存されます
言い方変えると、データベースに保存するためのデータをここでは入力してもらっている訳です(あれ?変わってないかな・・・)
データベースのuserテーブルにはいくつかカラムを作成していました
「name」「email」「password」「password_digest」です。
と、いうことで、この「name」はデータベースの「name」を表しており、ここではそこに入れるためのデータを入力するのに必要な形をHTMLで作って返しているというわけです。
ここでそれぞれのフィールドの特徴は以下のようになります
「text_field」
文字列を入れるだけ
「email_field」
見た目はtext_fieldと同じだが、スマホでここにカーソルをあてるとemail入力用のキーボードが表示されるようになる。ブラウザでは過去に入力したemailを自動で引っ張ってくる
「password_field」
ここに文字を入力すると、入力した文字⚫️になって表示され覗き見防止することができる
ついでに「submit」
これはボタン。よく「決定」とか「送信」とかである、一通り入力が終わったら押すやつ
今度はできた登録ページを見てみましょう。デベロッパーオプションでコードをのぞいてみると・・・
<%= f.label :name %>
<%= f.text_field :name %>
と書いてたはずの部分が
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
に、置き換えられちゃってます。
まさに、「name」に入れるデータを入力するにはこんな感じでHTMLにしたらよかばってん!・・・しましょうかね。という流れです。
続く「email」「password」「password_digest」においても、データベースのそこの部分に該当するデータを入れるために適したHTMLをそれぞれ作ってくれています。
今度はこちら
<input id="user_name" name="user[name]" type="text" />
ラベルは単なるタイトルなのでほっときましょう
特に「name="user[name]"」の部分ですが、「paramsのここに入ります!」ということを表しています・・・以上です。中途半端ですが、paramsは後ほど詳しく見ていくみたいです。
と、思いましたが少しだけみましょう
name="user[name]"はどこにいくのでしょうか・・・
それは、usersコントローラーのcreateアクションです。
ただ、createアクションで待ち構えているparamsには"params[:user]"と書かれてあります
params[:name]とあったならばまだわかりますが、何でなん?
他にもいろいろあってまとめられちゃっているのさ!
「email」にも「name="user[email]"」ってあるし、「password」にも「name="user[email]"」ってあるし、「password_digest」にも「name="user[password_digest]"」ってあるので、
ええ〜いめんどくさい!一個にまとめてしまえ!こいつらまとめて「[:user]や!!」
ということになってるだけの話です
「name=〇〇」でname属性と呼ばれるみたいですが、それは[:user]にひとまとめにされて、paramsに飛ばされてるのさ。ということを覚えておきましょう
7.3 ユーザー登録失敗#
フォームを理解するためには、ユーザー登録失敗の時が最も参考になるそうです。
失敗させましょう!6章で一生懸命作ったバリデーションが役に立ちそうです
ついでにエラーも表示させるようにするみたいです
7.3.1 正しいフォーム##
先ほどのおさらいですがもう一度このコードを見てみます
<form action="/users" class="new_user" id="new_user" method="post">
これは「action="/users"」と「method="post"」で、"/users"に"post(送信)"するよ〜。ということを表していました。
もちろん"/users"のどこよ。とも思いました。
それが**「createアクション」**です。
ここでは、「createアクション」の中で以下の機能を実装していきます
①フォーム送信を受け取り
②ユーザーを保存し
③再度送信用のユーザー登録ページを表示する
ひとまずコードを確認しましょう
def create
@user = User.new(params[:user]) # 実装は終わっていないことに注意!
if @user.save
# 保存の成功をここで扱う。
else
render 'new'
end
end
出てきましたねparams[:user]。
先ほど「name属性」がまとめてparams[:user]に送られる説明をしましたが、まさに「createアクション」でそれを新規ユーザーデータとして受け取っています。
新規ユーザーは@user
に代入され、その後はその@user
をどういう風に扱うかについて条件式にしています。
if @user.save
# 保存の成功をここで扱う。
else
render 'new'
end
至って簡単ですね。「もし新規ユーザーをデータベースに保存できたらほにゃらら」。「保存できなければほにゃらら」
保存できなかった場合は「render 'new'」とありましたね。。new(新規登録)画面に飛ばされます〜ということでしょう!
さてさて、ここは試しに「rails server」で情報を入力し、送信ボタンを押してみましょう。とありますので早速やってみると・・・エラー!!出ました。
が、ここで見るのはエラーではなくてRequestの部分
"user" => { "name" => "Foo Bar",
"email" => "foo@invalid",
"password" => "[FILTERED]",
"password_confirmation" => "[FILTERED]"
}
みたいな感じで書かれてあります。これがまさに先ほど説明した「[:user]にひとまとめにされて、paramsに飛ばされてる」を表しています。
@user = User.new(params[:user]) # この[:user]が上の"user"
なのでこのように書いても同じ意味を表します
@user = User.new(name: "Foo Bar", email: "foo@invalid",
password: "foo", password_confirmation: "bar")
なるほどね〜〜〜。めでたしめでたし。
とはなりません。さっき出たエラーを解消しなくちゃいけませんので
7.3.2 Strong Parameters##
エラーの解消の前に、一体何がエラーになっていたのかを知らないと何も始まりません。
入力フォームから受け取ったデータはparams[:user]で受け取って、それをsaveしてデータベースに流す感じで組み立てていましたが、今のままでは、登録フォームからどんな情報が来たとしても、それをそっくりそのままデータベースに保存しちゃえ。という状況です。
それはそれで非常に危険ということみたいです
主なリスクの要員となるのが、後の章でユーザーテーブルに追加する管理者権限(admin属性)です。
管理者として、サイトのデータベースに登録してしまえば他の登録者の情報見放題・編集し放題・削除し放題などといったことが可能になります。
いちユーザーにそんなことされたら一瞬でサイトが崩壊してしまうでしょう・・・
しかし・・しかしですよ、そもそも今のところ登録フォームには4つしか入力する箇所がありません。
なので、管理者権限を付与するかどうかを選択するフォームさえ作らなければいいジャン!と、素人はつい考えてしまいますが、頭の良い悪い人はそれができるのでしょう。。「admin=’1’」というのをWebリクエストに紛れこませるだけで管理者権限を奪いとることができるそうです。
・・・防止策として、**「Strong Parameters」**というテクニックを使います。
単純なものです。
アクションに送られてきたフォームの中で、許可するものを決め、あとは許可しないようにするだけみたいです。
params.require(:user).permit(:name, :email, :password, :password_confirmation)
パラメーターは「:user」に要求します。何を?「name」「email」「password」「password_confirmation」への許可をします。。。まんまですね。
「:user属性」がない場合はエラーになります。。
これで**「params[:user]」はダメーーーーということになりましたので、変わりに「user_params」メソッド**を使用します
@user = User.new(user_params)
これで同じような意味を表すことになるのですが、「user_params」メソッドなんてものは定義した覚えもありませんし組み込みヘルパーでもないので、当然どこかで定義しないと使えません。
なので定義します。usersコントローラーの中で。。。
今回のStrong Parametersusersはusersコントローラー内でしか使わないため、Rubyのコードである**「private」**を使います
これを使うことで、この「privateより」下に書かれたメソッドに関しては別のファイルからアクセスできませんよ〜ということになります
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
定義した「user_params」はこんな感じで入れ込みます
def create
@user = User.new(user_params)
7.3.3 エラーメッセージ##
「errors.full_messages」を使ってエラーメッセージを表示させる
「errors.full_messages」の役割は、「false」となり失敗した変数などにつけることで、エラーの内容に応じたメッセージを表示してくれます
画面上に出力するには**「form-control」**というCSSクラスを一緒に追加するとBootstrapがいい感じにしてくれます
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(model: @user, local: true) do |f| %>
<%= render 'shared/ error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %> # class: 'form-control'をつけるだけ
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %> # class: 'form-control'をつけるだけ
:
:
「form-control」のクラスをつけるのは分かりますが、「render 'shared/ error_messages'」とは何なんでしょうか・・・説明お願いします。
テキストには
『'shared/error_messages'というパーシャルをrender(描画)している点に注目してください』とだけ簡単にありました。
付け加えると
『これから作成する「shered」ディレクトリに入れた「error_messages」というエラーメッセージが入った便利ボックスから、必要に応じて適宜「render(表示)」させるようにする』
という感じでしょうか
(パーシャルとは必要なアイテムを入れた便利ボックスのこと)
「shared」フォルダはこれから作成するとありましたので、早速作成しましょう
なんで「shared」フォルダに入れるのかと言うと、分かりやすくするためです。本当は「views」フォルダの中だったらどこでもいいです・・・
$ mkdir app/views/shared
できたフォルダの中に「_error_messages.html.erb」というファイルを作成しまして、中身はコピペしときましょう!
<% if @user.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(@user.errors.count, "error") %>.
</div>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
「もし、エラーがあったら?」ということで始まってます。
エラーメッセージとして画面上に表示するのは<%= %>で囲まれた2つの部分ですね
まずはメソッドです
any?:ありますか?
count:何個あるか
これはおなじみのやつですね
次は**「pluralize」**です
これは英語の名詞を複数形にする時に大活躍します
使い方としては「pluralize(数,名詞)」みたいな感じで使われます
数が2つ以上だったら、名詞が英語の複数形表記になって表示されます
pluralize(2,man)だったら「5men」
pluralize(2,woman)だったら「5women」
<%= pluralize(@user.errors.count, "error") %>
このケースですと「@user.errors.count」が数。「error」が名詞の部分にあたり、"0 errors"、"1 error"、"2 errors"といった感じで表示されます。
もう一つ表示されるのがエラーメッセージになります
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
・・・元から「errors.full_messages」の中に準備されたエラーメッセージの中から、その時々で該当するものを出力する!といったものでしょうか。ここに関しては特につっこんだ説明はありませんでした。
あとはCSSを整えたら、表示されるエラーメッセージはとりあえず完成です。
7.3.4 失敗時のテスト##
失敗するデータを流し込んで失敗することを確認するテストを書くということですね
(ユーザー登録フォームを入力して、いざ「登録」を押した際に無効なデータを入れているがために登録に失敗しましたよーという動作をテストする)
まずは「rails generate」で統合テストを作成する今までにないパターンです
$ rails generate integration_test users_sign_up
まあ、「integration_test」が「統合テスト」って意味だから、「統合テストを生成する」というそのままのやつですけどね。
ここで、「countメソッド」が登場します。
数を出すだけの単純なメソッドで、特に定義するこもともなくどこでも使えるやつです。
$ rails console
>> User.count
=> 1
ユーザーの登録が一人ならデータが「1」と出力されます。不正なデータで登録をして、このカウントが増えてたらアウト!です
とりあえずここで記載するテストがこんな感じです
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
end
「integration(統合)」テストは「ストーリー」で作ります。
今回の例ですと、登録する場合の一連の流れをテストで書いていくイメージです。
上から見ていきましょう。見れば分かります。
まずは!
get signup_pathで登録画面にアクセスします
「assert_no_difference」:differenceが『違う』なので、「違わないですよね?」を確認している
で、何が「違わないですよね」かと言うと、 'User.count'(ユーザーの数)ですよ。
まとめると
**「ユーザーの数変わらんよね?」**を確認しています
何をしたらがブロックの中に書かれてあります
「post users_path」:users_path(ユーザーを作成するアクション)にpostリクエストを送信します
何を送るのか
paramsで受け取ったデタラメなデータを送る。ということで{ }内には明らかに検証をスルーしなさそうなデータが入っています。
Prock
まとめましょう
**デタラメなデータをユーザーを作成するアクションに送信しても、ユーザーの数は変わらんよね?**が、このテストの全容です。
あ、いやウソです
**「assert_template 'users/new'」**が残ってました
「assert_template」なんて初めて見ましたが(5章で出てきとるわボケが!!)、「適切なテンプレートが選択されているか」を確認するので、今回の場合だと、'users/new'の画面に戻っているかを確認しているのでしょう!
まとめましょう
**デタラメなデータをユーザーを作成するアクションに送信しても、ユーザーの数は変わらんよね?、んでその後また、新規登録ページが表示されますよね?**を確認しているのでしょう!きっと!
7.4 ユーザー登録成功#
これまでは、無効なデータを送り続けて失敗するケースばかりを見てきました。
これからやっと成功するケースを見ていきます。
成功するので、データはデータベースに登録されます。
そして登録に成功したら、プロフィールページに自動的に画面遷移させるようにます。
7.4.1 登録フォームの完成##
とりあえず、現状ではどういった動きをするのか見てみましょう
rails serverの登録フォームでバリデーションにかからない正しい値を入力し、「登録ボタン」を押してみますと・・・動きません!!
そりゃそうです。createアクションに対応するビューをまだ作ってませんから!
ただ今回は、そんなことはせずに先ほど書いたように「プロフィールページ」(いわゆるshowページ)に**「リダイレクト」するようにします。
ここで登場するのがその名の通り「redirect_to」メソッド**です。
今回はこんな感じで使ってます
redirect_to @user
登録したユーザーのところに飛ばすのね〜といったニュアンスが伝わりますが、これでOKなのが驚きです
実際はこういうことを表しているみたいです
redirect_to user_path(@user)
redirect_to user_path(@user.id)
redirect_to user_path(1)
=>/users/1
展開してみると分かりやすいですね・・・
こういうことをやっています「GET "users/#{@user.id}"」・・・@user.idにGETリクエストを送る
7.4.2 flash##
「flash」とは読んで字のごとくパッと出てきてパッと消えるタイプのメッセージです
こんな感じでsaveした直後に入れます
if @user.save
flash[:success] = "Welcome to the Sample App!"
「保存に成功したら"Welcome to the Sample App!"ってフラッシュで表示してねー」ということでしょう
で、いったいそれはどこで表示されるのかと言いますと、**「リダイレクトした直後のページ」**です
これで「flash」は完了!というわけにはいきません・・・
flash変数の内容をWebサイト全体にわたって表示できるようにする設定があります
これをレイアウトのヘッダー下に配置します
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
| message_type, message | では左の「message_type」がキー(success)。右の「message」が値("Welcome to the Sample App!")として扱われます。
alert-<%= message_type %>
これは・・・flash[:success]といった感じで「success」お願ーいとなってたら
alert-success
となり、「success」に対応するメッセージを引っ張ってきます。
ですのでflash[:danger]の場合は
alert-danger
となります。ちなみにあと「info」、「warning」の2つがあり、それぞれに適したメッセージを表示するようにします。
7.4.3 実際のユーザー登録##
ユーザー登録フォームからユーザー登録をやってみましょう!という話です。
まずはデータベースの中身をリセットします
$ rails db:migrate:reset
あとは、「rails server」開いていざ登録です。まあ、うまくいきますわな。。
登録がうまくいったら、「show」アクションに飛ばされ、「id」に「1」が振り分けられます。
7.4.4 成功時のテスト##
先ほど書いた失敗テストの成功バージョンを書いていきます
失敗の反対は成功!ということで先ほどとは反対の意味で書いていけばよさそうです
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { name: "Example User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
end
まさにそのまま反対になった感じですね
「invalid」が「valid」に
「assert_no_difference」が「assert_difference」に
「params: user」の中身も成功する内容に変わっています
「assert_difference」は「実行したブロックの直前と直後で結果が変わりますよ」という意味です。
さてさて問題は**「follow_redirect!」です
このメソッドは、POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動する**メソッドです
先ほどは失敗してたので、別のページに移動することなく同じnewページに留まっていました。
今回は成功したのでプロフィールページ(show)に移動するようにしています。
「assert_template 'users/show'」
7.5 プロのデプロイ#
プロレベルのデプロイをこんな初学者が・・・と怖気付いてしまいそうですが、動的ページをデプロイするならセキュリティをしっかりさせようということらっしいです。
ま、とりあえずトピックからmasterブランチにマージしときいましょう。
マージの流れは言うまでもないですが
$ git add -A
$ git commit -m "Finish user signup"
$ git checkout master
$ git merge sign-up
7.5.1 本番環境でのSSL##
ローカルのサーバーからネットワークに流れる前に、大事な情報を暗号化する技術(SSL)を使います。
※現在はSSLからTLSに名前が変わっていますが、SSLでも話が通るのでこちらで進めていくそうです・・・
今回は、とりあえずユーザー登録ページにSSLを導入します。
ユーザー登録ページ以外の他の部分については8章以降でなんとかしていくみたいです。
これをやることで、URLに鍵マークが付きます。セキュリティレベルが安全なサイトにランクアップですね。
SSLを有効化するのは超簡単です。
production.rbと言うファイルをチョチョイといじるだけで完了です
ここにある 👉 app > config > environmentsの中
まずは頑張って下のコードがあるところを探しましょう
# config.force_ssl = true
見つけたら「#」を外すだけで完了です。
ただし、これはあくまでローカル用の設定です。本番環境のWebサイトでSSLを使えるようにするには、ドメインごとにSSL証明書なるものを購入し、設定を噛ませる必要があります。
が、Heroku上でサイトを動かす場合はHerokuのSSL証明書に便乗する方法があります。これなら証明書を購入する必要はなさそうです。
ここら辺は、セキュリティについて少し突っ込んで勉強する必要がありそうです。
7.5.2 本番環境用のWEbサーバー##
SSL導入のお次は、アプリケーションの設定をいじって、本番環境に適したWebサーバーを使います。
HerokuのデフォルトがWEBrickというWebサーバーですが、問題ありのため変更します。
WEBrickは一人二人が使うんだったら、快適なのですが人数が増えると途端に雑魚になってしまって使い物にならなくなる特徴があるみたいです。。
そんなもんデフォルトにすんなよ・・・と言いたくなりますが今回は本番環境の設定をやっていますので多人数でも耐えられるPumaとかいうWebサーバーを使うように設定変更します。
Pumaを使うにはまずGemfileに追加することから始めます。
が、Pumaはデフォルトでも使えるようになってるみたいです。
Gemfileを開いてみると
gem 'bootstrap-sass', '3.4.1'
gem 'puma', '4.3.6'
gem 'sass-rails', '5.1.0'
Bootstrapの下にしれっと置いていました。
ここはクリアしたので、あとはHeroku上でPumaを走らせる設定ファイルを作成します。
そのためにはルートディレクトリ(一番上の階層)にProcfileというファイルを作成し、その中で、HerokuでPumaを使えるように設定します。
web: bundle exec puma -C config/puma.rb
7.5.3 本番データベースを設定する##
最後はデータベースの設定です。
チュートリアルの初めの方で、Gemfileを扱った際に
「rails migrate --without production」を使いましょうね。
みたいなくだりで、Herokuの本番環境ではPostgreSQLを使うからどうのこうのみたいな話がありましたね。
今回は、明示的に「PostgreSQL」使ってます!!
ということを示すようにします。
どこでかと言いますと、、、database.ymlというファイルです
ここにあります 👉 configの中
で、該当部分をコピペしときましょう。
7.5.4 本番環境へのデプロイ##
これで、本番環境用のWebサーバーとデータベースの設定は完了しました。
コミットして、デプロイしてみましょう!!
$ rails test
$ git add -A
$ git commit -m "Use SSL and the Puma webserver in production"
$ git push && git push heroku
$ heroku run rails db:migrate
7.6 最後に#
7章ではユーザー登録について見てきました。
ユーザーの扱いとしては、まだまだ始まりの段階でこれから「ログイン」とか「ログアウト」とか盛り沢山です。また、自分のアカウント情報を更新できるようにしたり、サイト管理者によるユーザー削除だったりとこれからどんどん機能を追加していきます。。。
7章の要約をようやく作り終えての感想#
RESTとか統合テストとか、以前出てきた内容が使われて復習にもなったし、フォームを利用したユーザー登録などの新しい概念も出てきたりと内容の濃い章でした。とにかく時間がかかったし、この章あたりから難易度がグググっと上がってきていると感じました。
最後、セキュリティに関しては駆け足でやっている感がありましたので理解度を深めるためには少し突っ込んで学習する必要があるかもしれません。。