Ruby on Rails

【Rails】form_withの使い方とストロングパラメーターによるレコード登録

投稿日:

こんにちは、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_torenderで次のビューに飛ばすように設定します

しかしform_withのオプションでlocal: trueとすることでHTTPメソッドがpostであっても、アクションに対応するビューを自動で読み込むようになります

今回の例で言えば、create.html.erbに画面遷移するようになります

このような機能なので必要に応じて使い分けるといいです

コントローラー側でのデータの受け取り方

先のform_withで受け取ったユーザーデータをコントローラーでレコード登録する方法を2パターンで紹介します

  1. ストロングパラメーター使用方式
  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というメソッドを使っています

これはnewsaveを同時にするメソッドです

つまり新規作成してそのままレコードに登録する機能があります

引数に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:ageparamsから取り出した値を対応させています

form_withでモデルをuserと指定している↓のでparams[:name]params[:age]ではうまくいきません

{user: {name: "<名前(文字列)>", age: <年齢(数値)>}} #paramsの中身

[:user]を経由する必要があります

この方式の方が何をしているのか分かりやすいですが、登録したい値の種類が多くなって来ると、記述量も増えていくので実務にはあまり向いていないと思われます

この記事は以上です

フォームやparamsの理解が深まるとRailsの力がかなり付くはずです!

それでは、また

-Ruby on Rails
-,

Copyright© 初心者のためのプログラミング独学ブログ , 2020 All Rights Reserved Powered by STINGER.