Railsチュートリアル 7章を終えました。
6章ではユーザモデルを作り、7章ではユーザ登録画面を作成していきます。
その要約です
リソース
ProgateのRailsコース内ではルーティングの際は基本的には
get '/help', to: 'static_pages#help'
のように、URLを指定した際に、コントローラのクラスおよびメソッドを指定して、ビューも同様にフォルダと表示するテンプレートを指定しました。
ここでルーティングにresources :users
と追加すると自動的に下記が追加されます。
HTTPリクエスト | URL | アクション | 名前付きルート | 用途 |
---|---|---|---|---|
GET | /users | index | users_path | すべてのユーザーを一覧するページ |
GET | /users/1 | show | user_path(user) | 特定のユーザーを表示するページ |
GET | /users/new | new | new_user_path | ユーザーを新規作成するページ (ユーザー登録) |
POST | /users | create | users_path | ユーザーを作成するアクション |
GET | /users/1/edit | edit | edit_user_path(user) | id=1のユーザーを編集するページ |
PATCH | /users/1 | update | user_path(user) | ユーザーを更新するアクション |
DELETE | users/1 | destroy | user_path(user) | ユーザーを削除するアクション |
Railsチュートリアル表 7.1: リスト 7.3のUsersリソースが提供するRESTfulなルートより
例えば、HTTPリエクストのGETメソッドでURLが/usersであれば、indexアクションと結びつきます。
また、テストコードの中で'get users_path'と記載すれば、indexアクションを呼べる。といった具合にアクションをレイアウトのなかで使用することができるようになります。
また、$ rails generate scaffold Users
のようにscaffold
でプロジェクトを生成した際も自動でresources :users
とルーティングが生成されます。
(progateからアプリを作った際にresourcesがわからなかった)
REST
REST(REpresentational State Transfer)とはRailsチュートリアルでは
アプリケーションを構成するコンポーネント (ユーザーやマイクロポストなど) を「リソース」としてモデル化することを指します。これらのリソースは、リレーショナルデータベースの作成/取得/更新/削除 (Create/Read/Update/Delete: CRUD) 操作と、4つの基本的なHTTP requestメソッド (POST/GET/PATCH/DELETE) の両方に対応しています。
要約すると、データベース操作もできるし、データベース操作とHTTP requestメソッドを対応させているデータ群のようです。
例えばデータベース作成(Create)とHTTPメソッド(POST)を対応させる。ということのようですね。
表 7.1のようなデータ群を一気に生成するためにresources :users
というのを使えばいいです。
フォーム
上記のようなユーザ登録フォームを作成するためにRailsではform_forヘルパーメソッドが用意されています。
Railsでこんな感じでフォームを書いていきます
<%= form_for(@user, url: signup_path) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %>
実際にアクセスしてhtmlで出力するとこうなります(hidden項目は削除しています)
<form class="new_user" id="new_user" action="/signup" accept-charset="UTF-8" method="post"> <label for="user_name">Name</label> <input class="form-control" type="text" name="user[name]" id="user_name" /> <label for="user_email">Email</label> <input class="form-control" type="email" name="user[email]" id="user_email" /> <label for="user_password">Password</label> <input class="form-control" type="password" name="user[password]" id="user_password" /> <label for="user_password_confirmation">Confirmation</label> <input class="form-control" type="password" name="user[password_confirmation]" id="user_password_confirmation" /> <input type="submit" name="commit" value="Create my account" class="btn btn-primary" data-disable-with="Create my account" /> </form>
簡易解説
ここで重要なのはラベルは<%= f.label :name %>
とすればhtmlで<label for="user_name">Name</label>
と
ラベルと中身が作成できます。
テキスト入力については<%= f.text_field :name %>
で<input id="user_name" name="user[name]" type="text" />
とtypeが自動で指定されます。
これは<%= f.email_field :email %>
でも同様です。
パスワード入力についても自動でtypeを指定します
<%= f.password_field :password %>
→<input id="user_password" name="user[password]" type="password" />
で、もうお気づきかもですが、htmlのname属性がどれもuser[(指定したfield)]
となっています。
これはfor文<%= form_for(@user) do |f| %>
で引数に@user
とすることでrailsはuser[]とnameを指定してくれます。
@userについてはコントローラで作成します。
さらにhtml上部で<form class="new_user" id="new_user" action="/signup" accept-charset="UTF-8" method="post">
とactionとmethodを指定しているのでボタン押下時にpost '/signup'
とルーティングを指定してあげると、指定したメソッドが動きます
@userをフォームの引数に指定してあげることで、あとはRailsが@userについてあとはよろしくやってくれます
エラーメッセージ
フォーム画面の中に<%= render 'shared/error_messages' %>
という、エラーメッセージ表示箇所があります。
この中ではエラーが発生した際はエラーを編集して表示する画面になります。
<% 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 %>
この中でエラーメッセージ定義箇所、<%= pluralize(@user.errors.count, "error") %>
はエラーカウントの数によって第二引数のerrorがなんと単数形か複数形に勝手になってくれます。
このpluralizeメソッドは複数形の場合に単にsをつけるだけでなく、例えば<%= pluralize(5, "woman") %>
とすると
"5 women"という具合に返してもくれます。すげぇ
Strong Parameters
フォーム送信時にparams[;user]
には入力したnameやemail等が入っています
ここで登録時に@user = User.new(params[:user])
とするとセキュリティ上の観点からエラーとなります
params[:user] の中にadmin属性などがある場合、curlコマンドをつかって
POST時にそれをtrueにすることが容易となり、アドミン権限を簡単に取得できるためです
ここでは、paramsハッシュでは:user属性を必須とし、名前、メールアドレス、パスワード、パスワードの確認の属性をそれぞれ許可し、それ以外を許可しないようにしたいと考えています。
そのためにはコントローラ層でStrong Parametersというテクニックを使うことが推奨されています。Strong Parametersを使うことで、必須のパラメータと許可されたパラメータを指定することができます。下記が例です。
params.require(:user).permit(:name, :email, :password, :password_confirmation)
flash
ユーザ登録を行なったりして、次画面に遷移した時に成功した旨のメッセージを出したい。
っといたように遷移した時だけメッセージを出して2回目以降のページ読み込みの際にメッセージを出さない時は
flashという変数が使えます。
具体的にはユーザ登録が終わると下記のような"Welcome to the Sample App!"というメッセージが一回だけでます
実装方法についてはコントローラで
flash[:success] = "Welcome to the Sample App!"
と定義することで、view側でflashをハッシュとして使用でき、
<% flash.each do |message_type, message| %>
とするとmessage_typeにはsuccess、messageには"Welcome to the Sample App!"が格納されますので、それを使用することができます。
テスト
フォーム画面の実装が済んだらテストを行います。入力テストの際はRailsにはフォーム用のテストを書くことができます。
これにより手でいちいち画面を入力せずに自動でテストが行えるようになります。
テスト作成
新規ユーザー登録用の統合テストを生成するところから始めていきます。コントローラーの慣習である「リソース名は複数形」に因んで、統合テストのファイル名はusers_signupとします。
$ rails generate integration_test users_signup
登録失敗時のテスト
まずはユーザ登録失敗時のテストを行うことにします。ここでは、失敗する入力を行い前後でユーザ数が変わっていないことを見ます
で具体的にはまず
①ユーザ登録画面にアクセスしget signup_path
②formが存在することassert_select 'form[action="/signup"]'
③失敗するデータを送信しその前後でユーザ数が変わらないことassert_no_difference 'User.count'
④失敗した時の画面遷移先が正しいことassert_template 'users/new'
⑤失敗した旨のメッセージが出ることassert_select "div#error_explanation"
などとすればいいかと思います
test "invalid signup information" do get signup_path assert_select 'form[action="/signup"]' 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' assert_select "body" do assert_select "div#error_explanation" end end
あとは$ rails test
で動かしてあげればいいです。
成功時のテスト
次にユーザ登録時の成功時のテストです。
①ユーザ登録画面にアクセスしget signup_path
③ユーザ登録に成功するデータを送信しその前後でユーザ数が変わること assert_difference 'User.count', 1 do
④次画面に遷移すること
⑤flashが表示すること
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' #flash有無検査。empty?を使う assert_not flash.empty? end
ここでfollow_redirect!
というのが出ていますが、このメソッドは、POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッドです。
あとは$ rails test
で動かしてあげればいいです。
参照
この記事を書く時にの参照先です。ありがとうございます。 www.masalog.site