Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtus: distinguish empty arrays from an unset attribute

I have several forms that submit to a Virtus object (through a controller). Some forms contain an extras attribute, others don't.

I currently can't distinguish whether extras has been set to an empty array (i.e. the user deselects all checkboxes on the form) or whether extras has never been submitted. In either case, extras will be an empty array.

I need this distinction because if the user deselects all extras I need to update them. On the other hand, if extras were not part of the form (i.e. not in the params), I shouldn't update them.

class UpdateForm
  include Virtus.model(nullify_blank: true)
  include ActiveModel::Model
  attribute :extras, Array
  attribute :booking_time, Time

  def save
    updatable_attributes = self.attributes.delete_if { |key, value| value.blank? }
    some_object.update(updatable_attributes)
  end
end

How can I make Virtus to give me a nil on extras if I call it like this:

UpdateForm.new(booking_time: Time.current)

Or is there a better pattern to do this?

like image 297
migu Avatar asked Oct 30 '22 21:10

migu


1 Answers

By default @extras attribute will be set to an empty array (even if you add default: nil to the attribute).
What you can do is to override initializer so it will set @extras to nil unless it was actually defined.
And use #nil? instead of #blank? which returns true on empty array.

class UpdateForm
  include Virtus.model(nullify_blank: true)
  include ActiveModel::Model
  attribute :extras, Array
  attribute :booking_time, Time

  def initialize(opts={})
    super
    @extras = nil unless (opts[:extras] || opts['extras'])
  end

  def save
    updatable_attributes = self.attributes.delete_if { |key, value| value.nil? }
    some_object.update(updatable_attributes)
  end
end
like image 128
Kirill Avatar answered Nov 15 '22 06:11

Kirill