Rails:Model.find() 或 Model.find_by_id() 以避免 RecordNotFound
Rails: Model.find() or Model.find_by_id() to avoid RecordNotFound
我刚刚意识到我的网站上有一个很难找到的错误。我经常使用 Model.find 从我的数据库中检索数据。
一年前,我合并了三个网站,导致需要处理大量重定向。为此,我在我的应用程序控制器中创建了一个 "catch all" 功能:
around_filter :catch_not_found
def catch_not_found
yield
rescue ActiveRecord::RecordNotFound
require 'functions/redirections'
handle_redirection(request.path)
end
此外,我在 routes.rb
:
的底部有这个
match '*not_found_path', :to => 'redirections#not_found_catcher', via: :get, as: :redirect_catcher, :constraints => lambda{|req| req.path !~ /\.(png|gif|jpg|txt|js|css)$/ }
重定向控制器有:
def not_found_catcher
handle_redirection(request.path)
end
我不确定这些事情是否与这个问题相关,但我想最好还是说一下。
我的实际问题
我经常使用 Model.find 从我的数据库中检索数据。假设我有一个带有这样控制器的产品模型:
def show
@product = Product.find(params[:id])
@product.country = Country.find(...some id that does not exist...)
end
# View
<%= @product.country.name %>
这是我在我的应用程序中大约 700 多个地方使用的东西。我今天意识到,即使会找到 Product 模型。调用 Country.find() 而 NOT find something 会导致 RecordNotFound,进而导致 404 错误。
如果在 .find-search 中找不到该国家/地区,我会根据以下预期制作我的应用程序 @product.country = nil
。我现在知道情况并非如此 - 它会创建一个 RecordNotFound。基本上,如果我加载 Product#show,我将得到一个 404 页,我希望在其中出现 500 错误(因为 @product.country = nil
和 nil.name
不应该工作)。
我的问题
我现在的大问题。我在我的应用程序中做错了什么,我应该总是使用 Model.find_by_id 来查询像我的 Country.find(...some id...)
吗?这里的最佳做法是什么?
或者,问题出在我在 Application Controller 中的 catch all 中吗?
回答您的问题:
我应该一直使用Model.find_by_id
如果您想通过 id 查找,请使用 Country.find(...some id...)
。如果您想找到其他东西,请使用例如。 Country.find_by(name: 'Australia')
。 find_by_name
语法在 Rails 4.
中不再受青睐
不过那是题外话,不是你的问题。
或者,问题出在我在 Application Controller 中的 catch all 中吗?
是的,这对我来说听起来像是痛苦的秘诀。我不确定您具体在做什么或您的重定向的性质是什么,但基于我对您尝试做的事情的模糊感觉,我将采用以下方法:
您的 Rails 应用程序不应该负责从您以前的网站/应用程序重定向路由。这应该是您的网络服务器的责任(例如 nginx 或 apache 或其他)。
本质上,您想列出所有要重定向的 URL 的大列表,以及要将它们重定向到的位置,然后按照您的网络服务器期望的方式格式化它们,并配置您的网络服务器来做为您重定向。搜索例如“301 redirect nginx”或“301 redirect apache”以查找有关如何设置的信息。
如果您有很多要重定向的 URL,您可能希望使用代码生成列表(大部分逻辑应该已经存在于您的 handle_redirection(request.path)
方法中)。
一旦您 运行 该代码并生成了列表,您就可以丢弃该代码,您的网络服务器将处理来自旧站点的重定向,并且您的 rails 应用程序可以愉快地运行在不知道以前的站点/URL 的情况下继续,并且在您的应用程序控制器中没有危险的包罗万象的逻辑。
这是一种非常有趣的异常处理方式...
在Rails中你使用rescue_from
来处理控制器层的异常:
class ApplicationController < ActionController::Base
rescue_from SomeError, with: :oh_noes
private def oh_noes
render text: 'Oh no.'
end
end
但是 Rails 已经通过提供静态 html 页面(其中 ActiveRecord::RecordNotFound
)处理了一些异常。你可以 override with dynamic handlers.
然而,正如@joshua.paling 已经指出的那样,您应该在服务器级别而不是在您的应用程序中处理重定向。
我刚刚意识到我的网站上有一个很难找到的错误。我经常使用 Model.find 从我的数据库中检索数据。
一年前,我合并了三个网站,导致需要处理大量重定向。为此,我在我的应用程序控制器中创建了一个 "catch all" 功能:
around_filter :catch_not_found
def catch_not_found
yield
rescue ActiveRecord::RecordNotFound
require 'functions/redirections'
handle_redirection(request.path)
end
此外,我在 routes.rb
:
match '*not_found_path', :to => 'redirections#not_found_catcher', via: :get, as: :redirect_catcher, :constraints => lambda{|req| req.path !~ /\.(png|gif|jpg|txt|js|css)$/ }
重定向控制器有:
def not_found_catcher
handle_redirection(request.path)
end
我不确定这些事情是否与这个问题相关,但我想最好还是说一下。
我的实际问题
我经常使用 Model.find 从我的数据库中检索数据。假设我有一个带有这样控制器的产品模型:
def show
@product = Product.find(params[:id])
@product.country = Country.find(...some id that does not exist...)
end
# View
<%= @product.country.name %>
这是我在我的应用程序中大约 700 多个地方使用的东西。我今天意识到,即使会找到 Product 模型。调用 Country.find() 而 NOT find something 会导致 RecordNotFound,进而导致 404 错误。
如果在 .find-search 中找不到该国家/地区,我会根据以下预期制作我的应用程序 @product.country = nil
。我现在知道情况并非如此 - 它会创建一个 RecordNotFound。基本上,如果我加载 Product#show,我将得到一个 404 页,我希望在其中出现 500 错误(因为 @product.country = nil
和 nil.name
不应该工作)。
我的问题
我现在的大问题。我在我的应用程序中做错了什么,我应该总是使用 Model.find_by_id 来查询像我的 Country.find(...some id...)
吗?这里的最佳做法是什么?
或者,问题出在我在 Application Controller 中的 catch all 中吗?
回答您的问题:
我应该一直使用Model.find_by_id
如果您想通过 id 查找,请使用 Country.find(...some id...)
。如果您想找到其他东西,请使用例如。 Country.find_by(name: 'Australia')
。 find_by_name
语法在 Rails 4.
不过那是题外话,不是你的问题。
或者,问题出在我在 Application Controller 中的 catch all 中吗?
是的,这对我来说听起来像是痛苦的秘诀。我不确定您具体在做什么或您的重定向的性质是什么,但基于我对您尝试做的事情的模糊感觉,我将采用以下方法:
您的 Rails 应用程序不应该负责从您以前的网站/应用程序重定向路由。这应该是您的网络服务器的责任(例如 nginx 或 apache 或其他)。
本质上,您想列出所有要重定向的 URL 的大列表,以及要将它们重定向到的位置,然后按照您的网络服务器期望的方式格式化它们,并配置您的网络服务器来做为您重定向。搜索例如“301 redirect nginx”或“301 redirect apache”以查找有关如何设置的信息。
如果您有很多要重定向的 URL,您可能希望使用代码生成列表(大部分逻辑应该已经存在于您的 handle_redirection(request.path)
方法中)。
一旦您 运行 该代码并生成了列表,您就可以丢弃该代码,您的网络服务器将处理来自旧站点的重定向,并且您的 rails 应用程序可以愉快地运行在不知道以前的站点/URL 的情况下继续,并且在您的应用程序控制器中没有危险的包罗万象的逻辑。
这是一种非常有趣的异常处理方式...
在Rails中你使用rescue_from
来处理控制器层的异常:
class ApplicationController < ActionController::Base
rescue_from SomeError, with: :oh_noes
private def oh_noes
render text: 'Oh no.'
end
end
但是 Rails 已经通过提供静态 html 页面(其中 ActiveRecord::RecordNotFound
)处理了一些异常。你可以 override with dynamic handlers.
然而,正如@joshua.paling 已经指出的那样,您应该在服务器级别而不是在您的应用程序中处理重定向。