form_for メソッド
Railsではrender
などを筆頭に、何かとよしなにやってくれるヘルパーメソッドがたくさんありますよね。
便利メソッドのおかげでユーザ登録フォームを一瞬で実装できたりと、Railsの生産性に驚くことが多いです。
ただ何かとよしなにやってくれすぎるおかげで、どういうパラメータの受け渡しをしているかのかをラップ(隠蔽)しすぎて、中身で何をやっているかがわからないままに実装できてしまったというケースもあると思います。(特に私のようにチュートリアルを見ながら勉強している人たちは...)
今回はフォーム作成のための便利メソッド、form_forについて自分なりにまとめてみることにしました。
お名前登録フォームを爆速で作ろう!!!
早速フォームを作ってみましょう。
ただし、単純化のために、今回用意したパラメータは一つ、名前のみです!!簡単でしょ??
このフォームを作るために必要なViewでのコードはこれだけです(Haml)↓
%h1 Write your name!
= form_for @user do |f|
= f.label :name, "名前"
= f.text_field :name
= f.submit "Send"
これで生成されるHTMLはどうなるかというと...
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓" />
<input type="hidden" name="authenticity_token" value="A5DQ4pmpmwnCYWind+TOL4SWMQm46kGWZVLXypyC8b9B4Z9GlzTjWG8NTqvs2cqg1bEEJ6Eq0kybasumXsPLGA==" />
<label for="user_name">名前</label>
<input type="text" name="user[name]" id="user_name" />
<input type="submit" name="commit" value="Send" />
Railsのよしなに力すごいですね。これだけのコードを生成してくれます。
form_forでは、渡したオブジェクト(今回では@user = User.new)に応じて、そのオブジェクトがどのモデルに属したオブジェクトなのかを勝手に判断してくれます。
Controller部分
今度はデータの受け取りのためにControllerに移ります。
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(params[:user])
@user.save
redirect_to new_user_path
end
end
Controller部分で@user
変数を作ってUserモデルのオブジェクトを入れておきます。この@user
変数をviewでform_forに渡すことによって、フォームが動作するようになります。
また、アクション名をnew
にすることにより、new.html.haml
のファイルを勝手に探しに行ってくれます。
それでは先ほど生成されたフォームに戻って、この部分。フォームのテキストエリアに入ったパラメータは、name
属性から引っ張ってくることができます。
<input type="text" name="user[name]" id="user_name" />
みたところ、params[:user]
みたいな感じでパラメータを取得できそうです。
しかしこれで実際にフォームの値を送信してみると...
現在ではこのデータの受け取り方は禁止されています。エラーも**Forbidden
**と、禁止の意を表しています。
昔のRailsではこれでいけたみたいなのですが、Rails4では引数に対する制限が厳しくなりました。
理由は、Userモデルが管理者を区別するadmin属性を持っていて、curlコマンドなどでadmin: true
のような属性を送った場合、管理者権限を持ったアカウントを作ることができてしまい、セキュリティホールに繋がるからです。
なので、現在のRailsでは基本的にStrongParametersという概念を用います。
とはいっても名前の通りで、**パラメータ受け取りの制限を強くするよ!!**というものです。
StrongParametersを適用すると、以下のようなControllerになります。
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
@user.save
redirect_to new_user_path
end
private
def user_params
params.require(:user).permit(:name)
end
end
params.require(:user).permit(:name)
の部分で、name
属性しか受け取らないという指定をすることが原則になりました。
完成!!
以上のコードで、本当に最低限のform_forヘルパーメソッドによるフォームの実装が完了します。
一応ちゃんと実装できてるか試してみます。
簡易コンソール用にDBに登録した名前を引っ張ってきてます。
息をするようにフォームが作れるようになるといいですね。form_tagヘルパの使い方はまだわかってないですが、またの機会に...