Как обрабатывать исключения, вызванные nil: NilClass

У меня есть модель под названием quiz, в которой много questions моделей. Я хочу добавить некоторую обработку исключения, чтобы, когда пользователь вводит неправильный quiz_id в URL-адресе, отображалась страница с ошибкой.

Я написал несколько вспомогательных методов в моем QuestionsController для обработки исключений:

private
def render_error(message)
    @error_message = message
    render 'error'
end

def active_quizzes_safe
    active_quizzes = Quiz.active_quizzes(current_user.id)
    render_error('Sorry! The request is invalid! Please log in again!') if active_quizzes.nil?
    active_quizzes
end


def active_quiz_safe(quiz_id)
    active_quiz = active_quizzes_safe.where(id: quiz_id).first
    render_error('The quiz does not exist or you are not allowed to take this quiz!') if active_quiz.blank?
    active_quiz
end

А вот действие в QuestionsController, в котором есть проблемы:

def show_quiz
  if current_user
    @quiz = active_quiz_safe(params[:quiz_id])
    @questions = @quiz.questions
  end
end

Поэтому, если :quiz_id в URL localhost:3000/MY_URL/:quiz_id неверен (т. Е. Запись не может быть найдена), страница с ошибкой должна быть отображена с помощью метода render_error. Однако, когда я устал от неправильного :quiz_id, я получил undefined method 'questions' for nil:NilClass. Я думаю, это из-за метода @questions = @quiz.questions в show_quiz.

Однако должно ли выполнение останавливаться после действия render_error, которое было до @questions = @quiz.questions? Почему @questions = @quiz.questions все равно исполняется?

Кроме того, существуют ли какие-либо стандартные способы обработки таких ошибок nil: NilClass?

Спасибо!!


person Lee7355512727    schedule 08.08.2013    source источник


Ответы (2)


Загляните в свои public/404.html, public/422.html and public/500.html файлы. Rails будет автоматически перенаправлять, если все равно произойдет ошибка. Поэтому я думаю, что вам не нужно вручную обрабатывать исключения, за исключением конкретного случая. Чтобы проверить и просмотреть страницы с этой ошибкой, запустите приложение в рабочей среде bundle exec rails s RAILS_ENV=production.

person hawk    schedule 08.08.2013

Вызов метода render не останавливает действие. Поэтому вам следует тщательно продумать свое действие, чтобы обеспечить возврат сразу после рендеринга. Нравится:

def show_quiz
  if current_user
    active_quizzes = Quiz.active_quizzes(current_user.id)
    if active_quizzes.nil?
      render_error('Sorry! The request is invalid! Please log in again!')
    else
      @quiz = active_quizzes_safe.where(id: quiz_id).first
      if @quiz.blank?
        render_error('The quiz does not exist or you are not allowed to take this quiz!')
      else
        @questions = @quiz.questions
      end
    end
  end
end

Но в этом случае я думаю, что лучше использовать некоторый контроль исключений, например:

def show_quiz
  if current_user
    active_quizzes = Quiz.active_quizzes(current_user.id)
    @quiz = active_quizzes_safe.find(quiz_id)
    @questions = @quiz.questions
  end
rescue ActiveRecord::RecordNotFound
  render_error 'The quiz does not exist or you are not allowed to take this quiz!'
end
person Jun Zhou    schedule 08.08.2013
comment
Большое спасибо! Кажется, что контроль исключений - единственный стандартный способ справиться с этим? Мне все еще нужно написать много других действий, так что это означает, что я должен добавлять одни и те же коды к каждому действию, которое не является СУХИМ. Просто не знаю, есть ли способ сделать контроллер тонким ... - person Lee7355512727; 08.08.2013