When to use FormObject 【Rails】
There are many design patterns in Rails, and one of them is “FormObject”. If you have studied Rails, you have used or at least heard of this. I think that it is easy to understand the design patterns, but it is difficult to use them properly. That’s why I wrote this article. When should I use “FormObject” ? I’m going to tell you my ideas with my experiences.
What is FormObject?
I think many readers have already known it, but in case that you don’t know it, I wrote the easy introduction.
FormObject is a model, and when your form becomes complex, it is usually used. It includes ActiveModel, so it can be dealt with as ActiveRecord model(ex. validation).
Case:1 you want to solve accepts_nested_attributes_for
When you want to change recored in multiple tables, you usually use accepts_nested_attributes_for. Of course, this method has many merits, but it makes the codes more complex. Some people don’t like it. Instead of it, FormObject can be selected. If you have shoes list web application. There are many shoes on the web page, and the application has 3 tables; shoes, reviews, sizes. When you want to save three objects simultaneously, you have to choose accepts_nested_attributes_for or FormObject. If you selected FormObject, the code would be below.
class PostForm include ActiveModel::Model attr_accessor :contents, :real_size def save(shoe)
shoe.save!
shoe.reviews.create!(contents: contents) unless contents.empty?
shoe.sizes.create!(real_size: real_size)
end
end
and
#controllerdef new
@form = PostForm.new
enddef create
@form = PostForm.new(shoes_params)
end
The code is easy by using FormObject.
Case2: When the validation is so complicated
If your form validations are so complicated and there are a lot of validations, you don’t want to use the class. Maybe you will get disappointed with the codes when you see them next time. How do we wrap this? For example, you are coding CsvImport class, and the class has many validations. You can write codes like below.
class CsvImport
include ActiveModel::Model
attr_accessor :file,
validates :name, presence: true
with_options on: :file do
validate :validationA
validate :validationB
validate :validationC
validate :validationD
validate :validationE
end def validationA
・・・・・・・・end
#controllerdef import
@csv_import = CsvImport.new
if @csv_import.valid?(:file)
@csv_import.save!
else
render 'new'
end
end
What if you write this code without wrapping like above and the number of validations are continuously increasing? Your code would be chaos in that case.
Wrap up
In a nutshell, when to use FormObject is like this.
- To avoid accepts_nested_attributes_for.
- There are many validations
Of course, there are other usages. I’m going to learn it.