Вловлюйте всі винятки в контролері рейок


89

Чи є спосіб вловити всі невловлювані винятки в контролері рейок, наприклад:

def delete
  schedule_id = params[:scheduleId]
  begin
    Schedules.delete(schedule_id)
  rescue ActiveRecord::RecordNotFound
    render :json => "record not found"
  rescue ActiveRecord::CatchAll
    #Only comes in here if nothing else catches the error
  end
  render :json => "ok"
end

Дякую

Відповіді:


92
begin
  # do something dodgy
rescue ActiveRecord::RecordNotFound
  # handle not found error
rescue ActiveRecord::ActiveRecordError
  # handle other ActiveRecord errors
rescue # StandardError
  # handle most other errors
rescue Exception
  # handle everything else
  raise
end

38
Хіба не правило НІКОЛИ ловити виняток?
РонЛюгге,

2
але як я можу зловити всі типи rescue => eлише в блоці?
Матриця

7
@RonLugge це повністю залежить від ситуації, що склалася. застосовувати "ніколи" як емпіричне правило - погана ідея.
Джастін Скілз,

11
@JustinSkiles Catching Exception виявить синтаксичні помилки (і сигнали переривання теж). Дайте мені один хороший сценарій для цього у виробничому коді. Я можу отримувати сигнали безпосередньо, але вам потрібно зробити це явно, щоб було зрозуміло, що ви створюєте обробник сигналів. Просто ловити виняток ... погана, погана ідея. Ловить навіть те, що не слід намагатися зловити.
RonLugge

6
Одним з небагатьох загальних випадків , коли це в здоровому глузді , щоб врятувати від Exception для лісозаготівель / звітності цілей, в цьому випадку ви повинні негайно ререйз виняток: stackoverflow.com/a/10048406/252346
aelesbao

198

Ви також можете визначити метод rescue_from.

class ApplicationController < ActionController::Base
  rescue_from ActionController::RoutingError, :with => :error_render_method

  def error_render_method
    respond_to do |type|
      type.xml { render :template => "errors/error_404", :status => 404 }
      type.all  { render :nothing => true, :status => 404 }
    end
    true
  end
end

Залежно від вашої мети, ви також можете розглянути можливість НЕ обробляти винятки на основі кожного контролера. Натомість використовуйте щось на кшталт дорогоцінного каміння винятків_для обробки, щоб послідовно керувати відповідями на винятки. Як бонус, цей підхід також буде обробляти винятки, що трапляються на рівні проміжного програмного забезпечення, такі як розбір запитів або помилки підключення до бази даних, які ваша програма не бачить. Exception_notifier дорогоцінний камінь може також становити інтерес.


4
Це ще зручніше, оскільки дозволяє ловити винятки СУХО.
m33lky

А якщо я використовую рятунок_фрому без параметрів? чи буде це поводитися так само, як порятунок? вловити всі помилки?
minohimself

2
Хіба це не погана практика rescue_from Exception? Я розумію, що краще рятувати StandardError, тому речі подобаються SyntaxErrorі LoadErrorне ловляться.
lobati

Так, погана форма порятунку "винятку". Дивіться "Винятковий рубін" Авді Грімма з причинами, чому це може бути проблематично.
Midwire

34

Ви можете визначити винятки за типом:

rescue_from ::ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from ::NameError, with: :error_occurred
rescue_from ::ActionController::RoutingError, with: :error_occurred
# Don't resuce from Exception as it will resuce from everything as mentioned here "http://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby" Thanks for @Thibaut Barrère for mention that
# rescue_from ::Exception, with: :error_occurred 

protected

def record_not_found(exception)
  render json: {error: exception.message}.to_json, status: 404
  return
end

def error_occurred(exception)
  render json: {error: exception.message}.to_json, status: 500
  return
end

2
Обережно, щоб не врятувати Exceptionбезпосередньо; см stackoverflow.com/questions/10048173 / ...
Тібо Barrere

10

rescue без аргументів врятує будь-яку помилку.

Отже, ви захочете:

def delete
  schedule_id = params[:scheduleId]
  begin
    Schedules.delete(schedule_id)
  rescue ActiveRecord::RecordNotFound
    render :json => "record not found"
  rescue
    #Only comes in here if nothing else catches the error
  end
  render :json => "ok"
end

8
Затхле питання, але ця відповідь неправильна. порятунок без аргументів обробляє лише StandardError robots.thoughtbot.com/rescue-standarderror-not-exception
Кіт Гаддіс

0

Насправді, якщо ви дійсно хочете вловити все , ви просто створюєте власну програму винятків, яка дозволяє налаштувати поведінку, якою зазвичай займається проміжне програмне забезпечення PublicExceptions: https://github.com/rails/rails/blob/4-2 -stand / actionpack / lib / action_dispatch / middleware / public_exceptions.rb

Купа інших відповідей ділиться дорогоцінними каменями, які роблять це за вас, але насправді немає жодної причини, коли ви не можете просто поглянути на них і зробити це самостійно.

Застереження: переконайтеся, що ви ніколи не створюєте винятків у своєму обробнику винятків. Інакше ви отримуєте потворний FAILSAFE_RESPONSE https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22

До речі, поведінка в контролері походить від пожежної: https://github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.