Form Objects Pattern in Rails
Bài đăng này đã không được cập nhật trong 4 năm
Khi bạn có một form phức tạp, một form phải xử lý 2,3, thậm chí nhiều object một lúc. Bạn sẽ làm như thế nào? Đối với tôi, thì tôi thường hay sử dụng Form Objects. Vậy tại sao lại dùng Form Object, và dùng nó như thế nào? thì bài viết hôm nay tôi sẽ đề cập đến điều này
Tại sao lại sử dụng Form Objects?
Bạn đã bao giờ nghe đến fat models
? Fat models
là gì?
Nó muốn nói về vấn đề, một model của bạn phải thực hiện quá nhiều nhiệm vụ, cả việc authentication
và accepting attributes
cho các model khác, dẫn đến tình trạng nó quá lớn. Và khi đó, model sẽ vi phạm một quy tắc rất phổ biến đó là the single responsibility principle
.
The single responsibility principle states that every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class.
Và đó là vấn đề của bài toán mà chúng ta đã đưa ra xử lý một form phức tạp
.
Và chúng ta giải quyết nó bằng Form Objects Pattern
.
Tiếp theo, chúng ta sẽ cùng ứng Form objects
trong một bài toán cụ thể.
Form Objects Pattern
1. Bài toán.
Chúng ta có một form để người dùng đăng kí sử dụng hệ thống của mình. Và ở trong đó, chúng ta yêu cầu người dùng nhập những thông tin cơ bản như: email, first_name, last_name
, ngoài ra chúng ta còn yêu cầu người dùng nhập thông tin của company
của họ như tên cty, địa chỉ
. Đồng thời thông báo cho admin của hệ thống biết về thông tin của người dùng đã đăng kí.
Rõ ràng ở đây, chúng ta cần xử lý lưu thông tin của 2 đối tượng cùng một lúc đó là: user
và company
, và thực hiện hành động gửi thông báo.
Chúng ta sẽ sử dụng Form objects pattern
cho bài toán này.
2. Form objects.
Bước đầu tiên, chúng ta sẽ tạo một Object cho form register, như sau:
#app/forms/registration.rb
class Registration
include ActiveModel::Model
attr_accessor :company_name, :company_address, :email, :first_name, :last_name
validates :company_name, presence: true
validates :company_address, presence: true
validates :email, presence: true, email: true
validates :first_name, presence: true
validates :last_name, presence: true
def save
if valid?
# Do something
# - create company
# - create user
# - send notifications
true
else
false
end
end
private
def create_company
# handle create a company
end
def create_user
# handle create a company
end
def sent_notifications
# sent notifications to admin
end
end
Ở đây, chúng ta thực hiện validations cho các thuộc tính như bình thường. Đồng thời viết thêm method save
tương tự như method save
mặc định của ActiveRecord, để thực hiện những action mà chúng ta cần thực hiện như: tạo company, tạo user, gửi thông báo.
Tiếp theo, thật quen thuộc, chúng ta sẽ thực hiện những gì giống như một form bình thường của Rails.
Tạo controller và views tương ứng thôi nào.
# app/controllers/registration_controller.rb
class RegistrationsController < ApplicationController
def new
@registration = Registration.new
end
def create
@registration = Registration.new registration_params
if @registration.save
# do something
else
render :new
end
end
private
def registration_params
params.require(:registration).permit :company_name, :company_address,
:email, :first_name, :last_name
end
end
# app/views/registration/new.html.erb
<%= form_for @registration do |f| %>
<%= f.label :company_name, t(".company_name") %>:
<%= f.text_field :first_name %>
...
<%= f.submit %>
<% end %>
Nhìn nó thật quen thuộc đúng ko
Và cuối cùng thì chúng ta cũng đã đạt được mục đích, form objects
chịu trách nhiệm nhận input đầu vào từ form và sau đó đưa nó đi đến từng model để lưu dữ liệu vào DB.
Lời kết
Với Form objects
chúng ta đã biết thêm một cách để xứ lý với những form phức tạp, thao tác với nhiều object. Nó sẽ giúp code của chúng ta được tổ chức một cách rõ ràng hơn.
Hãy cho tôi biết suy nghĩ của bạn !
Tham khảo
Link gốc: https://railsviet.com/form-object-pattern-trong-rails
Để thực hiện Form objects
một cách dễ dàng hơn, các bạn có thể tham khảo 2 gems này:
- Virtus: https://github.com/solnic/virtus
- Reform: https://github.com/apotonick/reform
Ngoài ra, trong bài viết này tôi có tham khảo một số tài liệu sau:
All rights reserved