scaffoldを利用したRailsアプリケーションの基本動作確認(続き)(2)
Userモデルのデータベースへの作成(createアクション)
Userモデルインスタンス生成(edit)画面から実際にusersテーブルへレコードを作成します。先ほどアクセスした画面でまずはform_forヘルパーで実際に生成されたformタグの中身をhtmlで覗いてみましょう。
ブラウザの検証ツールを用いてフォームタグを確認できます。以下の例ではブラウザにGoogle Chromeを用いています。nameのテキストフィールド付近で右クリックし、検証を選択すると検証ツールでフォームタグを確認できます。その様子が図3です。
フォームタグの通り、ここでCreate Userボタンをクリックしてsubmitすると、POSTメソッドで/usersパスにアクセスすることが分かります。前回で参照したルーティングを確認すると、POSTメソッド、/usersに該当するアクションはcreateであることが分かります。
コントローラーのcreateメソッドを確認します。
class UsersController < ApplicationController …(中略)… def create @user = User.new(user_params) respond_to do |format| if @user.save format.html { redirect_to @user, notice: 'User was successfully created.' } format.json { render :show, status: :created, location: @user } else format.html { render :new } format.json { render json: @user.errors, status: :unprocessable_entity } end end end …(中略)… private …(中略)… def user_params params.require(:user).permit(:name, :email) end end
createメソッドではまず、user_paramsというprivateメソッドを引数にしてUserモデルインスタンスをnewしています。Railsではフォームから送信されるデータはparamsという変数に格納されます。user_paramsメソッドではフォームからPOST送信されたデータが格納されているparams変数のうち、更新が許可された値であるname、emailのみを取得しています。具体的にはparams[:user][:name]、params[:user][:email]をPOST送信されたデータとして受け付けるソースコードとなります。これをparams.require(:user).permit(:name, :email)のように表現できるようになっています。これらの仕組みは、Strong Parametersといわれ、Rails 4より導入された機能です。
respond_toはRailsが提供するメソッドで、クライアントからのリクエストに応じてサーバーから返却するフォーマットによってレスポンスを定義します。respond_toのブロック内でformatタイプによって処理を分けることができます。scaffoldで自動生成したコードでは、リクエストがhtmlとjsonの場合でそれぞれレスポンスを定義しています。今回のようにhtmlフォームからアクセスした場合はクライアントからのリクエストがhtmlなので、form.htmlの行が実行されます。respond_toの後の行では、if文で@userインスタンス変数をsaveした実行結果によって処理を分岐しています。ActiveRecordが提供するsaveメソッドは成功すればtrue、失敗すればfalseを返却します。つまりsaveが成功した場合は上の行、失敗した場合は下の行が実行されます。
特にデータベースまわりの問題が発生しなければ、Create Userボタンをクリックするとsaveメソッドが成功するはずです。成功した場合はredirect_toによって生成した@userを表示する画面に遷移します。
[解説]createメソッドは対応するビューを持たない
createメソッドはPOSTでアクセスされた後、リダイレクトまたは直接別のメソッドに対応するビューファイルがrenderされます。例えば、saveメソッドが失敗した場合はrender :editとなっています。これはeditメソッドに対応するビューファイルであるapp/views/edit.html.erbを呼び出しています。
つまりcreateメソッドは対応するビューを持ちません。実際にls app/views/users/とすると分かりますがcreate.html.erbは存在しません。
$ ls app/views/users/
↓
_form.html.erb edit.html.erb index.json.jbuilder show.html.erb _user.json.jbuilder index.html.erb new.html.erb show.json.jbuilder
既存のUserモデルの表示(showアクション)
それでは実際にname、emailをテキストフィールドに入力してCreate Userボタンをクリックしてみましょう。ここではnameに「rails5_sample_user」、emailに「rails5_sample_user@test.com」と入力しました。Create Userボタンをクリックした後に表示される画面は以下の通りです。
アクセスされたURLに注目してみてください。このURLはルーティングを確認するとGETアクセスでURIが/users/:idの形式なので対応するアクションはshowアクションとなります。:idの部分がURLによると1となっているので、createメソッドのredirect_to @userの前の行でsaveメソッドが呼ばれます。その結果、usersテーブルにid=1のレコードがinsertされ、その後にusers.id=1のレコード内容を表示するshowメソッドにリダイレクトする、という動作になっています。
showメソッドの中身を見てみましょう。
class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update, :destroy] …(中略)… def show end …(中略)… private # Use callbacks to share common setup or constraints between actions. def set_user @user = User.find(params[:id]) end …(中略)…
showメソッドには何も処理が書いてありません。しかし実際にはusers.id=1のレコードの情報が表示されていますので何もしていないわけではありません。ソースコードをよく見てみると、2行目にbefore_actionという定義にshowがシンボルで記述されていることに気が付いたでしょうか。このように、before_actionによって指定したアクションメソッドがコールされる前に、特定の前処理をはさむことができます。このソースコードでは、show、edit、update、destroyメソッドが呼び出される前に、set_userメソッドが呼び出されます。set_userメソッドはprivateメソッドとしてコントローラー下部に記述されています。set_userメソッドでは、@userインスタンス変数にUserモデルをクライアントから送信されたparams[:id]変数でfindしています。このshowメソッドのケースでは、params[:id]=1ですので、User.find(1)の結果が@userインスタンス変数に代入されます。このようにActiveRecordのfindメソッドは引数のIDに一致するレコードをデータベースから取得します。
showアクションに対応するビューファイルを見てみましょう。
…(中略)… <p> <strong>Name:</strong> <%= @user.name %> </p> <p> <strong>Email:</strong> <%= @user.email %> </p> …(中略)…
ビューファイルの通り、@user.nameと@user.emailを画面に表示しています。createメソッドからリダイレクトされたshowメソッドで、直前にsaveされたUserモデルのレコードのnameとemailが表示されることの理由が明らかになりました。
なお、Backリンクをクリックすると、Usersリソース一覧(indexアクション)へ遷移します。以下の通り、追加されたusers.id=1のデータが表示されているでしょう。
既存のUserモデルの削除(destroyアクション)
一覧画面のDestroyリンクをクリックすると「Are you sure?」という確認ダイアログが出ます。OKをクリックするとレコードが削除されたメッセージとともに一覧画面が表示されます。既にレコードは削除されているので一覧画面にはUserモデルのレコードが消えていることが分かります。
class UsersController < ApplicationController …(中略)… def destroy @user.destroy respond_to do |format| format.html { redirect_to users_url, notice: 'User was successfully destroyed.' } format.json { head :no_content } end end …(中略)…
@user.destroyのdestroyメソッドはActiveRecordが提供するメソッドです。データベース上ではレコードを物理削除するdelete文が発行されます。レコード削除後、一覧画面のURLにリダイレクトしていることが読み取れます。
その他のアクション
既存のUserモデルの編集はeditアクション、更新はupdateアクションです。説明は割愛しますが、同様に対応するweb上での操作とソースコードを確認してみてください。editはshow同等、updateはcreate同等のコードであることが見て取れるでしょう。
まとめ
今回は、scaffoldで自動生成したソースコードと実際の動作を関連付けて各アクションについて解説しました。
次回はscaffoldで自動生成したユーザー登録機能をより実践的に拡張していきます。