Ruby on Rails 〜Formオブジェクトパターン〜
Formオブジェクトパターンとは?
デザインパターン
料理を作るときにレシピを見るように、railsでプログラムを記述する際にも レシピのようなものがあります。
料理のレシピは自分で試行錯誤せず、レシピを見れば手っ取り早くおいしい料理を 作ることができるのと同じように、Railsにも良いとされる手順や方法があります。
料理のレシピのように、要望にたいして最適な方法や手順をまとめたものを デザインパターンといいます。
Formオブジェクトパターン
1つのフォーム送信で複数のテーブルに保存したり、定義したクラスにform_withメソッドに対応する機能とバリデーションをかけたりを行う方法のことをFormオブジェクトパターンといいます。
実装の手順
新たにmodelsディレクトリにファイルを作成し、クラスを定義します。
作成したクラスにform_withメソッドに対応する機能とバリデーションを行う 機能をもたせるための記述をします。
class ItemOrder include ActiveModel::Model attr_accessor :name, :name_reading,... # バリデーションの処理 def save # テーブルにデータを保存する処理 end end
//ActiveModel::Modelをincludeすると、 このクラスのインスタンスはform_withやrenderなどの ヘルパーメソッドの引数として扱えたり、バリデーションを使えるようになります。
バリデーションの処理
class ItemOrder include ActiveModel::Model attr_accessor :name, :name_reading, :postal_code, :prefecture, :city, :house_number, :building_name, :price with_options presence: true do validates :name, format: { with: /\A[ぁ-んァ-ヶ一-龥々ー]+\z/, message: "is invalid. Input full-width characters." } validates :name_reading, format: { with: /\A[ァ-ヶー]+\z/, message: "is invalid. Input full-width katakana characters." } # 「住所」の郵便番号に関するバリデーション validates :postal_code, format: { with: /\A[0-9]{3}-[0-9]{4}\z/, message: "is invalid. Include hyphen(-)" } # 「注文価格」に関するバリデーション validates :price, numericality: { only_integer: true, message: "is invalid. Input half-width characters." } end # 「住所」の都道府県に関するバリデーション validates :prefecture, numericality: { other_than: 0, message: "can't be blank" } # 「注文価格」の金額範囲に関するバリデーション validates :price, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 1000000, message: "is out of setting range" } end
//numericalityは数値かどうかを検証するバリデーションになり、 オプション「only_integer:true」で整数のみという制限になります。
保存したい複数のテーブルのカラム名をすべて属性値として扱えるようにします。
データをテーブルに保存する処理
validates :price, numericality: {.... 省略 def save # ユーザーの情報を保存し、「user」という変数に入れている user = User.create(name: name, name_reading: name_reading) # 住所の情報を保存 Address.create(postal_code: postal_code, prefecture: prefecture, city: city, house_number: house_number, building_name: building_name, user_id: user.id) # 注文の情報を保存 Oder.create(price: price, user_id: user.id) end end
コントローラーのnewアクション、createアクションでFormオブジェクトのインスタンスを生成するようにします。
class ItemController < ApplicationController def index end def new @item_order = ItemOrder.new end def create @item_order = ItemOrder.new(item_params) #「UserDonation」に編集 if @user_donation.valid? @user_donation.save redirect_to action: :index else render action: :new end end private # 全てのストロングパラメーターを1つに統合 def donation_params params.require(:user_donation).permit(:name, :name_reading, :nickname, :postal_code, :prefecture, :city, :house_number, :building_name, :price) end end
フォーム作成の部分をFormオブジェクトのインスタンスを引数として渡す
<%= form_with(model: @Item_order, url: order_path, local: true) do |form| %> <%= render 'error_messages', model: @Item_order %>
これで、いつのフォームから複数のテーブルに保存ができ、 エラーメッセージの表示もできるようになります。