Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retain PORO Form object field inputs?

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
like image 947
robins_boss Avatar asked Oct 30 '25 08:10

robins_boss


1 Answers

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
like image 92
max Avatar answered Nov 02 '25 16:11

max



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!