Active Modelを定義し、form_forを使用、validatesでエラー処理までの流れ
画面の入力項目が一つのテーブルだけではないというのはよくあるパターン。
そうすると、form_forが使えないので、form_tagを使うことになります。
が、そうするとvalidatesの処理とかセオリー通りにいかないし、form_forの方がBootstrapでごにょごにょするのに便利なわけですし。
なんで、こういう場合は「そのformで使うモデルを独自に定義し、それを使う」という技があります。
※あと、検索画面で「検索条件欄に入力が無かったらエラーにしたい」というのをvalidatesで定義しておきたいとか。
というわけで、独自モデルの定義。
railsが5以上の場合は、app/modelの下にconcernsというフォルダが出来ているので、ここを使うらしい?
※ファイルの配置位置は、私の解釈なんで、間違っていたらご指摘ください。
「item_add.rb」というファイルを追加し、以下を記述
【model】
class ItemAdd
include ActiveModel::Model
attr_accessor :col_a, :col_b, :col_c
validates :col_a
presence: true,
length: {minimum: 1, maximum: 100}
end
ポイントは、赤字にした「include」のところで、ActiveModelを継承すること。
で、attr_accessorで、そのformで使う要素を列挙すること。
attr_accessorに書いた要素に対し、validatesを定義しておきます。
これは通常のModelに対する書き方と一緒。
で、この独自に定義したmodelをcontrollerでnewしてあげて、viewで使うわけです。
【controller】
def init
#独自定義のモデルをロードする
@add_form = ItemAdd.new()
end
【view】
<%= form_for @add_form, url: {controller: :xxx, action: :xxx} do |form| %>
<%= form.label :col_a, "要素A" %>
<%= form.text_field :col_a, id: :col_a%><br />
<%= form.label :col_b, "要素B" %>
<%= form.text_field :col_b, id: :col_b%><br />
<%= form.label :col_c, "要素C" %>
<%= form.text_field :col_c, id: :col_c%><br />
<br />
<%= form.submit "追加", class: :"btn btn-default" %>
<% end %>
これでview側で、form_forが使えます!
さて、これでsubmitされたら、validatesを通してチェックをしたいわけで、それはcontrollerでこんな感じで書きます。
【controller】
def xxx
#入力値を元にモデルオブジェクトを生成
add_form = ItemAdd.new(col_a: params[:item_add][:col_a], col_b: params[:item_add][:col_b], col_c: params[:item_add][:col_c])
if !add_form.valid?
#validatesでエラーになった場合の記述
flash[:danger] = add_form.errors.full_messages[0]
else
#validatesに問題がない場合の記述
end
end
ポイントは、赤字のnewしているところと、newしたオブジェクトに対し、valid?と判定をかけているところ。
newする時に、formでpostされたデータを入れてあげます。
その結果が正しいか(valid?)を確認し、falseが戻ってきたらエラーってことで、エラー処理を書けばよいです。
エラーのメッセージは、通常のmodelのvalidatesで戻されるのと同一です。
→エラーメッセージの日本語化について、追加の記事があります。