Рельсы 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_name
s.