The form object pattern helps keep your code clean by separating form handling from your database models. It makes complex forms easier to manage and test.
Form object pattern in Ruby on Rails
class MyForm include ActiveModel::Model attr_accessor :field1, :field2 validates :field1, presence: true def save return false unless valid? # custom save logic here end end
Use include ActiveModel::Model to get model-like behavior without a database table.
Define attr_accessor for form fields you want to handle.
class SignupForm include ActiveModel::Model attr_accessor :email, :password, :password_confirmation validates :email, presence: true validates :password, confirmation: true def save return false unless valid? User.create(email: email, password: password) end end
class OrderForm include ActiveModel::Model attr_accessor :product_id, :quantity, :user_id validates :product_id, :quantity, presence: true def save return false unless valid? Order.create(product_id: product_id, quantity: quantity, user_id: user_id) end end
This ContactForm object collects user input, validates presence of all fields, and simulates saving by returning true. It prints success or error messages.
class ContactForm include ActiveModel::Model attr_accessor :name, :email, :message validates :name, :email, :message, presence: true def save return false unless valid? # Imagine sending an email here true end end # Usage example form = ContactForm.new(name: "Alice", email: "alice@example.com", message: "Hello!") if form.save puts "Form saved successfully" else puts "Form has errors: #{form.errors.full_messages.join(", ")}" end
Form objects do not connect directly to the database like ActiveRecord models.
They are great for complex forms that touch multiple models or need custom validation.
Remember to test form objects separately from your database models.
Form objects keep form logic separate from database models.
They use ActiveModel::Model to behave like models without a table.
They help manage complex forms and validations cleanly.
Practice
Form Object in Rails?Solution
Step 1: Understand the role of form objects
Form objects are used to keep form-related logic and validations separate from the database models.Step 2: Compare with other options
They do not replace ActiveRecord models or speed up queries, nor do they generate HTML forms automatically.Final Answer:
To separate form validation and logic from database models -> Option CQuick Check:
Form object purpose = Separation of form logic [OK]
- Thinking form objects replace database models
- Assuming form objects speed up queries
- Confusing form objects with view helpers
Solution
Step 1: Identify the module for model-like behavior without DB
TheActiveModel::Modelmodule allows plain Ruby objects to behave like ActiveRecord models, including validations.Step 2: Eliminate other options
ActiveRecord::Baseis for database models,ActionController::Baseis for controllers, andActiveSupport::Concernis for mixins.Final Answer:
ActiveModel::Model -> Option AQuick Check:
Form object module = ActiveModel::Model [OK]
- Using ActiveRecord::Base in form objects
- Confusing controller modules with model modules
- Forgetting to include any module
user_form.valid? return if email is blank?
class UserForm include ActiveModel::Model attr_accessor :email validates :email, presence: true end user_form = UserForm.new(email: '') user_form.valid?
Solution
Step 1: Check validation rules
The form object requiresemailto be present (not blank).Step 2: Evaluate given input
Theemailis an empty string, which fails the presence validation, sovalid?returns false.Final Answer:
false -> Option BQuick Check:
Blank email fails presence validation = false [OK]
- Assuming blank string passes presence validation
- Expecting valid? to raise error on blank
- Confusing nil and empty string behavior
class OrderForm
include ActiveModel::Model
attr_accessor :quantity
validates :quantity, numericality: { greater_than: 0 }
def save
if valid?
Order.create(quantity: quantity)
end
end
endSolution
Step 1: Verify syntax and structure
The code properly includes ActiveModel::Model, defines attr_accessor, and sets up numericality validation. Syntax is valid.Step 2: Confirm behavior
Numericality validation internally handles string-to-number conversion (e.g., '5' validates as > 0). The save method returns the Order instance (truthy) on success or nil/falsey otherwise, which works in conditionals.Final Answer:
No error, code is correct -> Option DQuick Check:
Numericality handles strings; save pattern acceptable [OK]
- Thinking strings need manual conversion for numericality
- Overthinking save method's return value
- Assuming undefined models cause errors in examples
email, password, and password_confirmation. Which approach correctly ensures password confirmation validation and saves the user if valid?
class RegistrationForm
include ActiveModel::Model
attr_accessor :email, :password, :password_confirmation
validates :email, presence: true
validates :password, presence: true, confirmation: true
def save
if valid?
User.create(email: email, password: password)
end
end
endSolution
Step 1: Check validations for password confirmation
Theconfirmation: trueoption onpasswordautomatically validates thatpassword_confirmationmatches.Step 2: Verify save method logic
Thesavemethod callsvalid?and creates the user if valid, which is the correct pattern.Final Answer:
This code correctly validates and saves the user with password confirmation -> Option AQuick Check:
Password confirmation validation works with confirmation: true [OK]
- Manually checking password_confirmation equality
- Using deprecated validates_confirmation_of syntax
- Forgetting to call valid? before save
Ready to prove it?
Pass the test and this pattern moves unknown
