Поднять ActiveRecord:: RecordNotFound (или любой статус 404) для недействительной даты

В моем контроллере контроллера я использую Date.new для создания объекта даты, который должен быть передан в моем ActiveRecord.

end_range = Date.new(params[:year].to_i, params[:month].to_i, params[:day].to_i).end_of_day.to_formatted_s(:db)

Проблема с этим заключается в том, что если пользователь попытался вручную изменить параметры в URL-адресе, например, ввести 40 для параметра дня, Date.new завершается с ошибкой (как и ожидалось). Однако я бы предпочел не иметь ошибки 500, если пользователь набрал что-то подобное, но вместо этого ошибку 404 (потому что вы никогда не сможете записать запись с днем ​​40).

Я пробовал различные условные выражения (if и unless) до raise ActiveRecord::RecordNotFound, если это не удается, но оно возвращает ошибку 500 перед запуском условного (и поэтому никогда не возвращает 404).

Кто-нибудь знает лучший способ справиться с этим или способ позволить Date.new терпеть неудачу более изящно, чтобы условная инструкция могла работать?

Ответ 1

В этом случае вы можете спасти одно исключение и поднять другое, если хотите перекрыть исключения, которые не обрабатываются в следующих типах:

def show
  begin
    end_range = Date.new(...)
  rescue ArgumentError
    # Invalid date
    raise ActiveRecord::RecordNotFound
  end
rescue ActiveRecord::RecordNotFound
  render(:partial => 'not_found', :layout => 'application', :status => :not_found)
end

Возможно, было бы более эффективно просто выполнить рендеринг и потерпеть неудачу.

def show
  begin
    end_range = Date.new(...)
  rescue ArgumentError
    return render(:partial => 'date_not_found', :layout => 'application', :status => :not_found)
  end
end

Вы также можете сделать это в более широком смысле, используя метод rescue_from ApplicationController:

class ApplicationController < ActionController::Base
  rescue_from 'ArgumentError do
    render(:partial => 'exceptions/argument_error', :layout => 'application', :status => :not_found)
  end
end

Ответ 2

Я думаю, что имеет смысл спасать неверную ошибку даты с полезным сообщением. Это обычная проблема, например, когда люди выбирают 30 февраля. Я скорее отправлю их обратно в соответствующую форму и скажу им, почему их отправляют обратно. В большинстве случаев ошибка 404 будет неправильной, так как ошибка является недопустимым пользователем, а не недопустимым URL.

Кроме того, если вы спасите все ArgumentError, вы не получите уведомление о других ошибках, связанных с кодом. Поэтому, если это не ошибка даты, я повторно поднимаю ошибку. К сожалению, мы должны изменить тип исключения, чтобы избежать цикла.

Я положил это в application_controller:

rescue_from ArgumentError do |exception|
  if exception.message == 'invalid date'
    flash[:error] = exception.message
    redirect_to request.referer ? :back : root_url
  else
    raise StandardError, exception.message, exception.backtrace
  end
end