Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

accepts_nested_attributes_for, reject_if and has_one relationship not working together?

In my model I have

has_one :order, dependent: :destroy

accepts_nested_attributes_for :order, reject_if: lambda { |order| order[:description].blank? }, allow_destroy: true

For some reason, although the reject_if is tested and returns true (I checked that with the debugger), the nested order is not destroyed.

There is a lot of writing about this phenomenon on the internet, but I can't find a solution.

Does anybody know how to solve this?

like image 534
Danny Avatar asked Mar 15 '14 13:03

Danny


2 Answers

I finally created an intelligent "reject_if" setting the destroy flag on this specific occasion, as described in Destroy on blank nested attribute, but, to my own norms, this is not very "ruby", so can't imagine there is no better solution...

accepts_nested_attributes_for :order, allow_destroy: true, reject_if: lambda { |attributes|
  exists = attributes['id'].present?
  empty = attributes[:description].blank?
  attributes.merge!({_destroy: 1}) if exists and empty
  return (!exists and empty)
}
like image 51
Danny Avatar answered Oct 17 '22 00:10

Danny


From the nested_attributes API

You may also set a :reject_if proc to silently ignore any new record hashes if they fail to pass your criteria.

params = { member: {
  name: 'joe', order_attributes: [
    { description: 'Kari, the awesome Ruby documentation browser!' },
    { description: 'The egalitarian assumption of the modern citizen' },
    { description: '', _destroy: '1' } # this will be ignored
  ]
}}

Any hash with a blank description will be completly ignored, even if it has the _destroy flag.

If you want to remove records with a blank description, I can think of two solutions

Option 1: remove them with a callback at your model:

before_save :remove_orders_without_description

def remove_orders_without_description
  orders.select{|o| o.description.blank?}.each(&:delete)
end

Option 2: Remove the reject_if option at the model definition and use JS at the view to set the _delete attribute appropriately

like image 20
fjuan Avatar answered Oct 16 '22 23:10

fjuan