Mark Chavez
eat. sleep. repeat. 👾 coding, ⌨️ keyboarding, 🚴🏼 cycling.
Form Objects in Rails 12/29/2023
Example: Base form object class
class ApplicationForm
include ActiveModel::API
include ActiveModel::Attributes

def save
return false unless valid?
with_transaction { submit! }
end

private

def with_transaction(&block)
ApplicationRecord.transaction(&block)
end

def submit!
raise NotImplementedError
end
end
Example: Feedback form
class FeedbackForm < ApplicationForm
attribute :name
attribute :email
attribute :message

validates :name, :email, :message, presence: true

def submit!
FeedbackMailer.new(name:, email:, message:).deliver_later
end
end
Controller usage
class FeedbackController < ApplicationController
def create
form = FeedbackForm.new(
params.require(:feedback).permit(:name, :email, :message)
)
if form.save
redirect ...
else
render ...
end
end
end
Example: Base class with callback support
Note: There are instances when callbacks are preferred instead of adding logic to #submit! which is executed in the context of a DB transaction.

class ApplicationForm
...

define_callbacks :commit, only: :after
define_callbacks :save, only: :after

class << self
def after_save(method)
set_callback(:save, :after, method)
end
end
end