ユーザー管理機能のバリデーションについて
ユーザー管理機能のバリデーション設計で中々エラーを解決できなかったのでまとめておきます。
1つめのエラー(一意性)
User ユーザー新規登録 重複したemailが存在する場合は登録できないこと
Failure/Error: expect(@user.errors.full_messages).to include('Email has already been taken')
expected to include "Email has already been taken"
登録されたエラー文の中から'Email has already been taken'が出て欲しいが、エラー文が出ませんでしたということ。
上記バリデーションでemailが空では登録できないとしていたところを
上記でemailが空では登録できないかつ、登録されたことのあるものでは登録できない(一意性)と条件をつけると解決しました。
2つめのエラー(半角英数字混合)
2) User ユーザー新規登録 passwordが半角英数字混合であれば登録できる
Failure/Error: expect(@user.errors.full_messages).to include("Password には英字と数字の両方を含めて設定してください")
expected to include "Password には英字と数字の両方を含めて設定してください"
始め半角英数字混合でテストコードを作成しようとしていたが、それはできないようで1つずつ半角英文字がないと登録できないと、半角数字がないと登録できないとに分けて書いた。
また、エラー文を定型文でなく"Password には英字と数字の両方を含めて設定してください"にしていたこともエラーの原因のため定型文の "Password is invalid"に直した。
また、バリデーション の正規表現が適切でなかったため、上記のように変更した。
という形式で書く。
また、正規表現は以前間違えてエラーなどが出ていると、コードが合っていてもエラーが出ることがあります。その場合、エディタやターミナルを一度切って、再接続するとエラーが出ないことがあります。また、コピーで持ってきた正規表現をコピーし直すことも有効です。
deviseを使った場合の、form_withを分解して説明してみる。
form_withを何回調べてもよく詰まるので分解して記録しておきます。
deviseでユーザー管理機能(ログイン機能)を作成している時出てくる、
form_with
フォームを作成する。
model:@user
@userはdeviseで自動生成されるもので、登録されたユーザーの情報でmodels/user.rbから情報を持ってくる。
url:user_registration_path
rails routesでdevise/registration#createのPrefixに_pathをつける。
createアクションを見るのは、新規登録で保存するためnewからcreateへ送っている作業なので、HTTPメソッドがPOSTのものを確認する。
class
cssを適応している。
local: ture
HTMLとしてフォームを送信する場合必要であり、もしなければajax通信によるフォームの送信という意味になる。
deviseは色々自動生成してくれて便利だが、何をやってくれているか分かりにくいので気になることは都度調べていく。
エラーの原因箇所の見つけ方(NoMethodError)
NoMethodErrorの原因が中々わかりづらいので考え方を記録していきます。
まず、NoMethodError in Devise::Registrations#create
deviseの新規登録時のcreateアクションのメソッドがない。
undefind method 'day'for"1=>1930,2=>1,3=>2":string
dayというメソッドがない。"1=>1930,2=>1,3=>2"は新規登録の年号。stringはREADME.mdで作成したtype。
f.date_select
日付の入力に特化した選択ボックスを生成するメソッド。
ここからNoMethodErrorだから何か定義してないのかな?と考えるもdayは自分で定義していない。
f.date_selectは、公式ドキュメントを見ても構文通り。
undefind method 'day'for"1=>1930,2=>1,3=>2":string
のstringは文字列を表す物なのに日付の数字に使っている。
ここがおかしいかもしれないと、stringを記述しているREADME.mdを見るとTypeがstringになっている。
日付に使うdateに直すと、エラーがなくなった。
まとめ
今回エラー文で気づかなければいけないのは、日付にsrting(文字列)を使っていること。
ユーザー管理機能を作っているのにREADME.mdは見直さないので、日付はdateを使うこと覚えていないと中々気づけない。
いくら自由に検索してもいいとは言え、ある程度の基礎知識は頭にないとつまづくポイントが増えることに気づかされた。
rails migration defaultについて
railsでmigrationファイルのdefaultについて調べてもあまり明確なものがなかったため記録しておきます。
マイグレーションファイルでこのような記述がある。
このdefault:""は初期値が空欄だということを示しています。
emailとencrypted_passwordはdeviseで自動生成されており、その時defaultも自動生成されますが、消しても問題ないようです。(空欄なので消す意味もありませんが)
上のものを追記したい時、初期値を空欄にしたい場合、default: ""はつけるとエラーが出ることがあります。そのため書かない方が無難です。
まとめ
defaultは初期値を表しています。
emailとencrypted_passwordはdeviseで自動生成され、同時にdefaultも作られています。
空欄のためにdefault: ""を追記する必要はない。
HTTPメソッドのGETとPOSTの違いについて
HTTPメソッドのGETとPOSTの違いがはっきり分からず用途に困ったため、簡潔にまとめます。
GET → 要素を取得するだけの場合に使用する。
例えば、検索情報などをform_withで取得する時など。
POST → 要素を取得してデータベースを介して保存する場合に使用する。
例えば、新規登録などデータベースに情報を記録したい場合など。
HTTPメソッドを学んだ時はあまり違いを理解せず、GETは取得する、POSTは送信する、と覚えていましたが少し理解を深めたいところです。
Routing Errorについて
No route matches [GET] "/users"
とはHTTP VerbがGETかつパスが"/users"のものがないよ、という意味です。
HTTP VerbはHTTPメソッドのことで全部で8つあります。
GET→URIのデータを取得する。
POST→URIにリソースを追加する。
HEAD→URIのヘッドデータだけ取得する。
PUT→URIの内容を作成、置換する。
DELETE→URIの内容を削除する。
OPTIONS→URIに対して利用できるメソッドを取得する。
CONNECT→プロキシにトンネリング通信を要求する。
TRACE→クライアントからのリクエストをそのまま返す。
上記を参照しています。
Routes match in priority from top to bottom
と書かれているのは下の表にルーティング出したから、そこにあれば繋がるよ、という意味でヒントのようなものです。
ちなみに、ターミナルに「rails routes」と入力すると画像下の表の部分が出るのでそちらでも問題ない様です。
今回はhttp://localhost:3000を開こうとして、その前にエラーが出ている画面http://localhost:3000/usersで再読み込みしようとしてルーティングエラーが出ていた様です。
http://localhost:3000/usersはエラー特有のページらしいのでローカルで確認する場合で、前の作業でエラーが出ていた場合気をつけないといけないそうです。
検索してもあまりいい記事がないため、備忘録として残しておきます。
エラーが出た箇所を修正したつもりでもエラーが消えない時に見直すこと
エラーが出た時に、エラー検索して何が違うのか理解し、その箇所を訂正したつもりでもエラーが消えないことはないでしょうか?
何度か気づかずエラー解消に苦労したので備忘録として残しておきます。
教材でprojectディレクトリのAに例題、Bに演習で使ったアプリがある場合、例題でAのターミナルを開いて作業をしていたとします。その後Bで演習を始め、localhostを確認した時にエラーが出ます。
この場合Bのターミナルやエディタを確認しなければならないのは当然なのですが、その前に作業していたAでターミナル操作をしていたため、いくらAを確認してもBのエラーが解消しないということが起こっていました。
以上からcdで自分がどこにいて、何の操作をしているのかよく意識して作業を進めないと根本的な間違いに気がつかないことがあることを学びました。
エディタやターミナルに慣れてくると起こらないかも知れませんが、不慣れな自分は何度かこのために悩み続けることになってしまいました。