Рельсы 3.1: как приложение может обрабатывать различные "причины" для ActiveRecord::RecordInvalid (например, дубликат или ошибка проверки)

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

Я хотел бы перенаправить в разные места, в зависимости от того, какая проверка вызвала ошибку: неверный формат или дубликат.

В моем коде у меня есть

    begin
      user.save!
      flash[:notice] = "Created new user #{email} with password #{password}"

    rescue ActiveRecord::RecordInvalid => e
      flash[:alert] = "Failed to create account because #{e.message}"
      redirect_to SOMEPLACE
    end

Если адрес электронной почты имеет недопустимый формат (например, "user@example"), e.message имеет вид "Ошибка проверки: адрес электронной почты недействителен"

Если электронное письмо уже существует в таблице, e.message будет "Проверка не удалась: электронная почта уже получена"

Я ненавижу идею разбора текста e.message, чтобы определить причину... есть ли лучший способ для обработчика спасения обнаружить основную причину, которая вызвала исключение ActiveRecord::RecordInvalid?

PS Я знаю, что в этом примере я могу просто проверить уже существующее электронное письмо перед сохранением, но я пытаюсь понять общее решение для обнаружения различных действий проверки и реагирования на них, выдавая одно и то же исключение.

2 ответа

Стандартный способ Rails сделать это - не использовать оператор bang, который вызывает исключение, а использовать стандартный метод save и проверить, вернул ли он true или false:

if @user.save
  flash[:notice] = "User created."
  redirect_to :action => :index
else
  flash[:alert] = "User could not be created."
  render :action => :new
end

И в вашем представлении создания пользователя:

<% if @user.errors.any? %>
  <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
  </ul>
<% end %>

Если я понимаю, что вы пытаетесь сделать правильно, один из способов сделать это - просто заявить о наличии ошибки на уровне поля. например

if user.errors[:field_name].present?
  redirect_to path_for_field_name_error
end

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

redirect_to REDIRECT_PATHS[field_name] if user.errors[:field_name].present?

где вы можете просто перебрать field_names.

Другие вопросы по тегам