##form_withはフォームにす関するHTML要素を簡単に生成することができる便利なメソッド
まずフォームの値をデータベースに保存する際の書き方です。
↓railsでこう書くと
<%= form_with(model: @user, local: true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
↓HTMLを生成してくれます。
<form accept-charset="UTF-8" action="/users" method="post">
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]"
type="password" />
<label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
name="user[password_confirmation]" type="password" />
<input class="btn btn-primary" name="commit" type="submit"
value="Create my account" />
</form>
では、内部構造を見ていきます。
<%= form_with(model: @user, local: true) do |f| %>
model @userの部分はviewを呼び出したコントローラー側で、作成したインスタンスです。
def new
@user = User.new
#新しいuserインスタンスを作成。
end
つまり「model: @user」の@userは空のインスタンスです。
railsは空のインスタンスをmodelに渡すと、**「フォームの内容で新しくユーザーを作成したいだろうからcreateアクションにPOSTリクエスト投げるね」**と勝手に解釈してくれます。
逆に言うと@userにデータがある場合は**「ユーザー情報の更新がしたいんだね」**と解釈してupdateアクションにPATCHリクエストをなげてくれます。
↓createアクションにPOSTリクエストを投げる時は、このように作成してくれます。
<form accept-charset="UTF-8" action="/users" method="post">
↓id:1のユーザー情報を編集する時は、このように生成してくれます。
<form accept-charset="UTF-8" action="/users/1" method="post">
<input type="hidden" name="_method" value="patch">
httpリクエストでPATCHリクエストは存在しないので、 inputタグで偽造します、
これも自動生成されます。
ブロック引数のfは、HTML要素を生成するメソッドを持っています。
引数は**「:カラム名」**とします。
<%= f.label :name %>
<%= f.text_field :name %>
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
勝手にfor,id,name,type名を設定してくれます。
name属性が「user[name]」となっているので、コントローラーで値を受け取る場合は、「params[:user][:name]」とすると取得できます。
email,passwordも同じ様な感じで生成されます。
<%= f.label :email %>
<%= f.email_field :email %>
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<%= f.label :password %>
<%= f.password_field :password %>
<label for="user_password">Password</label>
<input id="user_password" name="user[password]" type="password" />
##モデルのインスタンスを渡さないでパスを書くこともできます。
<%= form_with(url: "/users", local: true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
↓このようなHTMLが生成される。
<form accept-charset="UTF-8" action="/users" method="post">
<label for="name">Name</label>
<input id="name" name="name" type="text" />
<label for="email">Email</label>
<input id="email" name="email" type="email" />
<label for="password">Password</label>
<input id="upassword" name="password"
type="password" />
<label for="password_confirmation">Confirmation</label>
<input id="password_confirmation"
name="password_confirmation" type="password" />
<input class="btn btn-primary" name="commit" type="submit"
value="Create my account" />
</form>
url指定、user[name]みたいなname属性にはなりません。
ただしform_withの引数に**「scope: :スコープ名」を追加するとname属性は「スコープ名「name」」**のようになりモデルを渡した時と同じ実装ができます。
↓試しにスコープを追加してみます。
<%= form_with(url: "/users",scope: :user, local: true) do |f| %>
↓先ほどのモデルを渡した時と同じようなHTMLが作成されました。
<form accept-charset="UTF-8" action="/users" method="post">
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]"
type="password" />
<label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
name="user[password_confirmation]" type="password" />
<input class="btn btn-primary" name="commit" type="submit"
value="Create my account" />
</form>
##コントローラー名やアクション名を指定することもできます。
基本はモデルを渡せばrailsが自動で振り分けてくれますが、ルーティングがうまく動かない時は、直接コントローラー名やアクション名を指定できます。
<%= form_with @user, url: {controller: 'users', action: 'index' } do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
##view側でformに渡すモデルを作成しても動きます。
先ほどはコントローラーでモデルを作成し、viewに渡していました。
def new
@user = User.new
#新しいuserインスタンスを作成。
end
<%= form_with(model: @user, local: true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
ですがモデルはコントローラーで作成しなければいけないわけではないので、以下のようにviewでモデルを作成することもできます。
<%= form_with(model: User.new, local: true) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
#参考
https://pikawaka.com/rails/form_with
https://railstutorial.jp/