こんにちは、Shinyaです
投稿が長らく空いてしまいました。約20日間、良く言えば休息、実際はモチベ低下によるさぼりを続けていました。しかしそろそろまた動き始めます。静と動、陰と陽、生と死、更新と非更新、人生には人間にはあらゆる物事には二面性があります。それが行ったり来たりするだけで、それを否定してはいけないと思うんです。二面性を恥じない
連想余談はここまでにして、今回はRuby on Railsのform_with
メソッドで値をコントローラーに送る際のオプションと値をレコードとしてテーブルに登録する方(ストロングパラメーター)を解説していきます
Railsにおいて値を保持する重要な役割を持つparamsについても触れます。
form_withでデータをコントローラーへ送る
以下はform_with
を用いてuserモデルのレコードを新規作成する際の記述の一例です
名前と年齢の情報を収集するフォームを形成しています
<%= form_with model: @user, url: "/users", method: :post, local: true do |f| %>
<%= f.text_field :name %>
<%= f.text_field :age %>
<%= f.submit "送信" %>
<% end %>
ちなみにWEBページでは以下のようなHTMLとして読み込まれます
<form action="/users" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="XoItYTyBM/E5FzjWBq9Sk3+aE2ncsMM8m3DqZRntbJVJExsjIjhM0fBp1+1nNdgcFzjGiBTTU4yWOMs+gt+cow==">
<input type="text" name="user[name]" id="user_name">
<input type="text" name="user[age]" id="user_age">
<input type="submit" name="commit" value="送信" data-disable-with="送信">
</form>
ここから上記の例で使っているform_with
のオプションについて解説していきます
model: の役割
form_with
はモデルに絡めてフォームを作ることも(form_for的に)、絡めずに作ることも(form_tag的に)できます
上記の例はuserモデルに絡めています
それを指定している部分がmodel: @user
の部分です
@userはコントローラー側で@user=User.new
として用意されたインスタンス変数なので、絡めるモデルはuserモデルということになります
url: の役割
url:
は名前の通り、フォームデータの送信先のURLを指定するためのオプションです
今回の例では"/users"
というURLを指定していますが、ルーティングで同じURLを受け取るようにすれば実際はなんでも良いでしょう("/hoge"
でも)
post '/users', to: 'users#create'
method: の役割
method:
はHTTPメソッドを指定します
レコード登録の為にデータを送るような場合であればpostとします
指定したHTTPメソッドは当然ながらルーティングで対応させるようにしましょう
local: true の役割
HTTPメソッドをpostとした場合、アクションに対応するビューはデフォルトでは読み込まれません
例えばルーティングでpost '/users', to: 'users#create'
としてusers_controllerのcreateアクションに流れた場合、アクションの処理が完了したらそこで画面遷移は起きません
なので通常はredirect_to
やrender
で次のビューに飛ばすように設定します
しかしform_with
のオプションでlocal: true
とすることでHTTPメソッドがpostであっても、アクションに対応するビューを自動で読み込むようになります
今回の例で言えば、create.html.erbに画面遷移するようになります
このような機能なので必要に応じて使い分けるといいです
コントローラー側でのデータの受け取り方
先のform_withで受け取ったユーザーデータをコントローラーでレコード登録する方法を2パターンで紹介します
- ストロングパラメーター使用方式
- paramsの値を直で記述する方式
(前提:createアクションでレコード登録する場合を想定しています)
1.ストロングパラメーター使用方式
def create
@user = User.create(user_params)
end
private
def user_params
params.require(:user).permit(:name, :age)
end
@user = User.create(user_params)
という記述があります
左辺の@userの部分は別にただのuserでも構いません
インスタンスとして次の処理に情報を渡したい場合はインスタンス変数にすれば良いです、さもなくばただの変数で良いです
右辺ではuserモデルの対してcreate
というメソッドを使っています
これはnew
とsave
を同時にするメソッドです
つまり新規作成してそのままレコードに登録する機能があります
引数にuser_params
が入っていますが、これはどこから来たのでしょうか?
private
の記述の下にuser_params
というメソッドが定義されています
private
以下にはクラス内でのみ使用可能なメソッドを書きます
つまりuser_params
というUsersController
クラス内でのみ使えるメソッドをcreate
アクション(=メソッド)で呼び出してるという形になっています
ではuser_params
メソッドでは何をしているのでしょうか?
params.require(:user).permit(:name, :age)
とあります
params
にはform_with
で収集した値(value
)がハッシュ形式でまとめて格納されています
こんな感じです↓
{user: {name: "<名前(文字列)>", age: <年齢(数値)>}} #paramsの中身
このハッシュから必要な値だけをレコードに登録します
今回登録したい値はユーザーの名前と年齢です
違う言い方をすると、params
というハッシュからキー :user
に対応する値の中のキー:name
とキー:age
に対応する値を取り出すということになります
params
はハッシュが入れ子になっていますので、値を取り出すまでにキーを2階層分追う必要があります
実はこの「キーを2階層分追う」ということをuser_paramsメソッドではしています↓
params.require(:user).permit(:name, :age)
まずrequire
メソッドでキー:user
を指定しています(モデルの選択)
次にpermit
メソッドでキー:name
と:age
を指定しています(モデルのテーブルに属するカラムの選択)
このようにすることで欲しい値だけをparams
から取り出すことができます
しかし、初心者からすると必要性がよく分からないかもしれません
なぜならform_with
でユーザーの名前と年齢を入れるように指定していますから、それがparams
に乗ってくるはずだからです
実はこのように厳格に取り出す値を指定することにはセキュリティ上の理由があります
簡単にいうと、悪意あるユーザーがparams
に要求していない変な値を乗っけてくる可能性があるためです
そう言った悪意ある値を取り出してレコードに登録してしまわないために、paramsの値を確認せずに全て登録するような処理にはしないのです
2.paramsの値を直で記述する方式
def create
@user = User.new(name: params[:user][:name], age: params[:user][:age])
@user.save
end
こちらはuser_params
メソッドを使わずに直で引数にparams
の値を書く方式です
@userのキー:name
と:age
にparams
から取り出した値を対応させています
form_with
でモデルをuserと指定している↓のでparams[:name]
やparams[:age]
ではうまくいきません
{user: {name: "<名前(文字列)>", age: <年齢(数値)>}} #paramsの中身
[:user]
を経由する必要があります
この方式の方が何をしているのか分かりやすいですが、登録したい値の種類が多くなって来ると、記述量も増えていくので実務にはあまり向いていないと思われます
この記事は以上です
フォームやparamsの理解が深まるとRailsの力がかなり付くはずです!
それでは、また