I've created a R-o-R Form object which takes in attributes and then saves those attributes to some nested objects, however, upon failing the validations, the input values disappear. Is there anyway to retain them?
class FormObject
include ActiveModel::Model
attr_accessor(:name, :date)
def initialize(params = {})
@params = params
end
def save
return if invalid?
no = NestedObject.new(nested_object_params)
no.save
end
def nested_object_params
@params.permit(:name, :date)
end
end
and this is the controller
class Controller
def new
@form = FormObject.new
end
def create
@form = FormObject.new(form_object_params)
if @form.save
redirect_to ...
else
render :new
end
end
def form_object_params
params.require(:form_object).permit(:name, :date)
end
end
CodePudding user response:
The problem is most likely that you have overridden the initialize method without calling super. This messes up the whole attibute mapping done by ActiveModel::AttributeAssignment
which the form really relies on to be able to fetch the attributes of your model.
class FormObject
include ActiveModel::Model
attr_accessor(:name, :date)
def initialize(params = {})
@params = params
super
end
def save
return if invalid?
no = NestedObject.new(nested_object_params)
no.save
end
def nested_object_params
@params.permit(:name, :date)
end
end
If you use ActiveModel::Attributes
instead of Ruby's built in attr_accessor
you get type casting just like with ActiveRecord backed attributes.
But this is a straight up disaster as you now have three different representations of the same data:
- the instance variables on your FormObject
- the hash stored in @params
- the attributes stored in NestedObject
Instead you should probally rethink this completely and use delegation:
class FormObject
include ActiveModel::Model
attr_accessor :object
delegate :name, :name=, :date, :date=, :save, to: :object
def intialize(**attributes)
@object = NestedObject.new(attributes)
super
end
end