Lチカ開発ブログ

https://l-chika.com/の開発ブログ

ActiveModelのベストプラクティスを考える

ActiveModelとは

ActiveModelとは こちら にあるように Modelと直接紐付けないような、フロントのフォームに密接に関わるバリデーションを実装する場合に便利な Module。

課題

ActiveModel を利用シーンの一つとして、一つフォームで複数のモデルを扱うことがある。

その際によく迷うことがある。

  • モデルのバリデーションが ActiveModelApplicationRecord のモデルとで重複する
  • データの作成と編集で ActiveModelintialize にどうやって、何を渡すか(ここらへん情報が検索してもあまり見つからなかった)

解決方法

そこで、とりあえず考えた解決方法

  • ActiveModel に対象のモデル群を内包する
  • find, save, valid? を実装
  • ActiveModel のバリデーションはフォーム固有のものだけを実装し、モデルで実装されているバリデーションはモデルに任せる
  • Controllercreate,update はフォームの内容を, edit の場合は保存されている内容からフォームを作成できるようにする
  • save 時に valid? を実行し、内包するモデルのバリデーションエラーとフォームのバリデーションエラーを全てフォームのエラーに追加する

以下イメージ。実際の動作確認はしてないです

class HogeController < ApplicationController
  der new
    @hoge_form = HogeForm.new()
  end
   
  der create
    @hoge_form = HogeForm.new(params[:hoge_form])
    if @hoge_form.save
        ...
    else
        ...
    end
  end
   
  def edit
    @hoge_form = HogeForm.find(parmas['id'])
  end
  
  def update
    ...
  end
...
 
calss HogeForm
   include ActiveModel
    
   attr_accessor :hoge_a, :foo_b
   
   validates :hoge_a, presence: true
   validates :foo_b, presence: true
    
   class << self
      def find(id)
        hoge = Hoge.find id
        new(hoge: hoge.attributes, foo: hoge.foo.attributes)
      end
   end
 
   def intialize(params = {})
     @hoge = Hoge.new(params[:hoge])
     @foo = Foo.new(params[:foo])
   end
 
  def valid?(context = nil)
    super
     
    @hoge.valid?
    @hoge.errors.each do |k, v|
      errros.add(k, v)
    end
    
    @foo.valid?
    @foo.errors.each do |k, v|
    ...
  end
   
  def save
     return unless valid?
     
     return false unless @hoge.save
     @foo.save
  end
end

関連のおすすめ本

Ruby on Rails 5 超入門

Ruby on Rails 5 超入門