Общее спасение всего контроллера, когда id не найден - RoR
Я наткнулся на ситуацию, когда мое приложение ищет идентификатор, который не существует в базе данных. Вызывается исключение. Конечно, это довольно стандартная ситуация для любого веб-разработчика.
Я знаю, что использование спасения с ситуацией довольно аккуратно, например:
def show
@customer = Customer.find(params[:id])
rescue ActiveRecord::RecordNotFound #customer with that id cannot be found
redirect_to action: :index #redirect to index page takes place instead of crashing
end
Если клиент не может быть найден, пользователь будет перенаправлен на индексную страницу. Это работает абсолютно нормально.
Теперь это все хорошо, но мне нужно выполнить те же попытки восстановления в таких действиях, как show, edit, destroy и т.д., т.е. каждый метод контроллера, которому нужен определенный идентификатор.
Сказав, что здесь мой вопрос:
Разве нет способа вообще сообщить моему контроллеру, что если он не может найти идентификатор в любом из своих методов, он должен перенаправить на индексную страницу (или, как правило, выполнить определенную задачу)?
Ответы
Ответ 1
Для этой задачи вы должны использовать rescue_from
. См. Пример в Обзор контроллера действий.
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
private
def record_not_found
redirect_to action: :index
end
end
Ответ 2
Rails имеет встроенный метод rescue_from
:
class CustomersController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :index
...
end
Ответ 3
Если вы говорите об этом в одном контроллере (в отличие от этого в глобальном масштабе в каждом контроллере), вот несколько вариантов:
Вы можете использовать файл before_filter для настройки вашего ресурса:
class CustomerController < ApplicationController
before_filter :get_customer, :only => [ :show, :update, :delete ]
def show
end
private
def get_customer
@customer = ActiveRecord.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to :action => :index
end
end
Или вы можете использовать метод вместо этого. Я двигался в этом направлении, а не использовал переменные экземпляра внутри представлений, и это также помогло бы вам решить вашу проблему:
class CustomerController < ApplicationController
def show
# Uses customer instead of @customer
end
private
def customer
@customer ||= Customer.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to :action => :index
end
helper_method :customer
end
Ответ 4
В некоторых случаях я рекомендую использовать Model.find_by_id(id)
, а не Model.find(id)
. Вместо того, чтобы бросать исключение, .find_by_id
возвращает nil
. если запись не найдена.
Просто убедитесь, что nils избегают NoMethodError
!
P.S. Для того, что стоит, Model.find_by_id(id)
функционально эквивалентен Model.where(id: id)
, что позволит вам построить дополнительные отношения, если вы хотите.