[Rails] Action View Form Helpers
keywords: form_for
, fields_for
FormHelper @ Ruby on Rails API Action View Form Helpers @ RailsGuides FormTagHelper @ Ruby on Rails API FormBuilder @ Ruby on Rails API
速查
form_for
keywords: form_for(record, options = {}, &block)
form_for @ Rails API
<%= form_for :post do |f| %> <!-- 等同於: form_for 'post' -->
<!-- 直接在 form_for 帶入 model object -->
<%= form_for @post do |f| %> <!-- 等同於下面的寫法 -->
<%= form_for @post, as: :post, url: post_path(@post), method: :patch, html: { class: "edit_post", id: "edit_post_45" } do |f| %>
<!-- -->
<%= form_for(Post.new) do |f| %> <!-- 等同於下面的寫法 -->
<%= form_for @post, as: :post, url: posts_path, html: { class: "new_post", id: "new_post" } do |f| %>
<!-- 透過 format 可以指定回傳的資料型態 -->
<%= form_for(@post, format: :json) do |f| %>
:url
: 如果沒代的話預設會是傳到當前的 URL:html
: 使用其他和 html 相關的 attributes:method
: get, post, patch, put, delete:remote
: 設為true
時,為允許 Unobstrusive JavaScript drivers 控制表單發送的行爲,預設這個行為會是 AJAX Submit。:format
:設定要求回傳的檔案型態。:as
: 預設所有<input name="">
中的name
都會是該 model 的名稱,例如@post
的當中的 input (form.text_field :title
)欄位,會編譯成<input name=post[title]>
,因此在 controller 就可以透過params[:post]
去取得各欄位的內容。若想要改變 name 的值就可以使用 :as。:authenticity_token
: 只有在想要客製化 authenticity_token 或者不使用它時(false
)才會加上這個選項:enforce_utf8
:namespace
: 會在 form 當中的 id 欄位都加上指定的 namespace 作為前綴
使用範例
<%= form_for @post do |form| %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title, id: :post_title %>
</div>
<div class="field">
<%= form.label :description %>
<%= form.text_area :description, id: :post_description %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
<!--
<form class="edit_post" id="edit_post_1" action="/posts/1" accept-charset="UTF-8" method="post">
-->
處理 Model 中不存在的屬性
使用 form_for
時,其中的欄位必須是 Model 有的屬性,那如果資料庫沒有這個欄位時,你需要在 Model 程式中加上存取方法,例如:
class Event < ActiveRecord::Base
#...
def custom_field
# 根據其他屬性的值或條件,來決定這個欄位的值
end
def custom_field=(value)
# 根據value,來調整其他屬性的值
end
end
這樣就可以在 form_for
裡使用 custom_field
了:
<%= form_for @event do |f| %>
<%= f.text_field :custom_field %>
<%= f.submit %>
<% end %>
記得把 :custom_field
也加到 Strong Parameters 清單裡,這樣按下送出後,就可以跟著 @event
本來的欄位一起處理了。
- Form Helper @ RubyOnRails org
- Form Builder @ RubyOnRails org
form_with
keywords: form_with(model: nil, scope: nil, url: nil, format: nil, **options)
form_with @ Rails API
- :model: 使用
model
後會自動會表單加上url
和scope
- :scope: 用來為表單中的
<input name="">
欄位增加 namespace 的 prefix - :method
- :format
- :authenticity_token
- :local: 如果不希望使用
remote: true
,可以加上local: true
預設的情況下,如果 Unobstrusive JavaScript driver 有使用的話(rails-ujs
),那麼使用 form_with
會直接添加 <form data-remote="true">
,並透過 XMLHTTPRequest 來送出請求。
<%= form_with model: @post do |form| %> <!-- 等同於下面那行 -->
<%= form_with scope: :post, url: post_path(@post), method: :patch do |form| %>
<%= form_with model: Post.new do |form| %> <!-- 等同於下面那行 -->
<%= form_with scope: :post, url: posts_path do |form| %>
select
<!-- select -->
<%= form.select :game, options_for_select(game_options_for_select), { prompt: '--請選擇--' }, { class: 'form-control', required: true } %>
<%= select_tag :question_type, options_for_select([["訂單問題"], ["退貨問題"], ["購買問題"], ["技術問題"]]), { prompt: '--請選擇--', class: 'form-control', required: true } %>
<!--
<select name="question_type" id="question_type" required="required">
<option value="">請選擇您的問題分類</option>
<option value="訂單問題">訂單問題</option>
<option value="退貨問題">退貨問題</option>
<option value="購買問題">購買問題</option>
<option value="技術問題">技術問題</option>
</select>
-->
select_tag @ RailsGuides
# options 中的陣列:[顯示的文字, 實際的 value]
def enum_options(enum_field, selected = nil)
options = enum_field.collect { |key, _| [key.humanize, key] }
options_for_select(options, selected)
end
讓第一個選項(prompt)不能被選取
直接在 select tag 上加上
required
,Bootstrap 即會判斷,是否已有被選取
def gender_options(selected = nil, prompt: nil)
options = [['Male', 'male'], ['Female', 'female'], ['Other', 'other']]
# 如果有寫 prompt 且沒有選擇 selected 的項目則添加進去
options.unshift([prompt, nil, hidden: true, selected: true]) if prompt.present? && selected.blank?
options_for_select(options, selected)
end
<%= form.select :gender, gender_options(prompt: ' Gender '), {}, class: 'custom-select' %>
options for select @ Rails API