0

I have same problem and dont understand how to realise it's idea. Here's my code:

controller.rb

def update
  begin
    dot_applications = DotApplication.where(id: params[:ids])
    bad_dot_app_update = []
    dot_applications.each do |dot_application|
      if dot_application.update!(lead_source_id: resource_params[:lead_source_id])
        dot_application.update!(lead_source_id: resource_params[:lead_source_id])
      else
        bad_dot_app_update << dot_application.update!(lead_source_id: resource_params[:lead_source_id])
      end
    end

    render dialog: {
      close_dialog: true,
      success_message: "The lead source was changed for selected applicants."
    }
  rescue StandardError => error
    render dialog: {
      close_dialog: true,
      error_message: "Can't update lead sources because #{error.message}"
    }
  end
end

I want to collect not updated 'dot_aplication' add it to array and insert it to rescue StandartError. Help me please.

Community
  • 1
  • 1
  • Are you getting any error? Anyway, check if this helps: https://stackoverflow.com/questions/3694153/catch-all-exceptions-in-a-rails-controller – iGian Aug 30 '18 at 15:17
  • I updated controller. But i am not sure what it's will be work correct. – tandem tour Aug 30 '18 at 15:23
  • Your current code will "abort" the first time an `update!` fails - so there's no point trying anything with "adding errors to an array" just yet (there can only ever be 1 error). What behaviour do you want, if some of the `DotApplication`s fail to update? Update none of them? Or update some of them? – Tom Lord Aug 30 '18 at 16:42

2 Answers2

0

This is done quite simple. If you call #update! instead of #update the code will raise an exception when the first record fails, jumping to the rescue block (thus halting further updating of records).

You can achieve the result you want by calling #update inside a #group_by block, grouping the records based on their save state:

dot_applications = DotApplication.where(id: params[:ids])
saved = dot_applications.group_by do |dot_application|
  dot_application.update(lead_source_id: resource_params[:lead_source_id])
end

# Saved records will be in `saved[true]` unsaved records will be in
# `saved[false]`. If all records saved `saved[false]` will be `nil`. If none of
# the records saved `saved[true]` will be `nil`.

if saved[false]
  # some (or all) records didn't save
  unsaved_ids = saved[false].pluck(:id).join(', ')
  render dialog: {
    close_dialog: true,
    error_message: "The following selected applicants didn't save: #{unsaved_ids}"
  }
else
  # success
  render dialog: {
    close_dialog: true,
    success_message: "The lead source was changed for selected applicants."
  }
end
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
0

You should be using update rather than update! because the minute an exception is catched, your code execution will be halted and redirected to the rescue block. update on the other hand only returns false on failure.

Try something like this:

def update

  dot_applications = DotApplication.where(id: params[:ids])
  bad_dot_app_update = dot_applications.reject do |dot_app| # Reject element where updates are successfull
    dot_application.update(lead_source_id: resource_params[:lead_source_id])        
  end

  if bad_dot_app_update.any?
    # Here you can access the array and do whatever you want.
    errors = bad_dot_app_update.collect {|bad_dot_app| bad_dot_app.errors }
    # Collecting errors, only needs formating for printing
    render dialog: {
      close_dialog: true,
      error_message: "Can't update lead sources because #{error.message}"
    }
  else
    render dialog: {
      close_dialog: true,
      success_message: "The lead source was changed for selected applicants."
    }
  end
end
pelarejo
  • 109
  • 7