分离出表单对象(Form Objects)
https://github.com/angelfan/DayDayUp/blob/master/note/form_object.md#%E5%88%86%E7%A6%BB%E5%87%BA%E8%A1%A8%E5%8D%95%E5%AF%B9%E8%B1%A1form-objects
分离出表单对象(Form Objects)
step1
class SignupForm
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :user_name, department_id
validates :user_name, presence: true
def save
if valid?
# balabala
else
false
end
end
def persisted?
false
end
end
缺点:
- 属性没有类型
- 设定default 值不是很方便
step1
借助 Virtus 增加default值
class SignupForm
include ActiveModel::Model
include Virtus
# Attributes (DSL provided by Virtus)
attribute :user_name, String
attribute :department_id, Integer default: 1
# Validations
validates :user_name, presence: true
def save
if valid?
# balabala
else
false
end
end
end
resource
- gem reform
- gem virtus
- gem simple_form_object
- Creating Form Objects with ActiveModel and Virtus
- Form Objects in Rails
other solution
form sharetribe
module FormUtils
module_function
# Define a form class that can be used with ActiveSupport form bindings
#
# Usage:
#
# -- in some_controller.rb --
#
# MyForm = FormUtils.define_form("MyForm", :name, :password)
# .with_validations { validates_presence_of :name }
#
# def new
# render locals: { form_obj: MyForm.new }
# end
#
# def create
# myForm = MyForm.new(params[:my_form])
# if myForm.valid?
# ...
#
def define_form(form_name, *ks)
Class.new(Object) { |klass|
include ActiveModel::Validations
include ActiveModel::Conversion
@__keys = ks
@__form_name = form_name
@__validation_blocks = []
def self.keys
@__keys
end
def self.validation_blocks
@__validation_blocks
end
attr_reader(*ks)
def initialize(opts = {})
keys_and_values = self.class.keys
.map { |k| [k, opts[k]] }
.reject { |(k, v)| v.nil? }
keys_and_values.each { |(k, v)|
instance_variable_set("@#{k.to_s}", v)
}
instance_variable_set("@__value_hash", Hash[keys_and_values])
end
def persisted?
false
end
def to_hash
@__value_hash
end
def self.model_name
ActiveModel::Name.new(self, nil, @__form_name)
end
def self.with_validations(&block)
@__validation_blocks << block
class_exec(&block)
self
end
}
end
def merge(form_name, *form_classes)
keys = form_classes.map(&:keys).flatten
validation_blocks = form_classes.map(&:validation_blocks).flatten
form = FormUtils.define_form(form_name, *keys)
validation_blocks.each do |block|
form.with_validations(&block)
end
form
end
end
SignupForm = FormUtils.define_form("SignupForm", :user_name, :department_id)
.with_validations { validates_presence_of :user_name }