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 = nilnil.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 已经指出的那样,您应该在服务器级别而不是在您的应用程序中处理重定向。