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 %>

これで、いつのフォームから複数のテーブルに保存ができ、 エラーメッセージの表示もできるようになります。