我认为您的意思是显示,因为索引实际上是用于列表/集合的。你应该去.first
那里,否则你只是有关系,对吧?然后,用于.first!
引发错误,因为 Rails 4 public_exceptions中的 Rails 机架中间件将以基本方式处理,例如
def show
# need to do to_s on params value if affected by security issue CVE-2013-1854
@bar = Bar.where(:foo_id => params[:id].to_s).first!
end
您也可以使用@bar = Bar.find(params[:id])
,但已弃用,将在 Rails 4.1 中删除,之后您必须添加gem 'activerecord-deprecated_finders'
到 Gemfile 才能使用。
对于索引,您可能需要@bars = Bar.all
. 如果由于某种原因您想要过滤而不想要范围等,那么您可以使用@bars = Bar.where(...).to_a
或类似的。
Rails 4:Rack 中的基本异常处理是自动的
只要查询开始出现错误,Rails 4 就应该能够返回错误的消息部分,因为where to_(format)
可以在哈希上调用任何支持的格式(例如 json、xml 等)。
要了解原因,请查看 Rails 的 Rack public_exceptions中间件。
如果是 html,它将尝试从 Rails 的公共目录中读取相关文件以获取状态代码(例如500.html
,对于服务器错误/HTTP 500)。
如果是其他格式,它会尝试to_(the format)
在 hash: 上做{ :status => status, :error => exception.message }
。要查看它是如何工作的,请转到 Rails 的控制台:
$ rails c
...
1.9.3p392 :001 > {status: 500, error: "herro shraggy!"}.to_xml
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <status type=\"integer\">500</status>\n <error>herro shraggy!</error>\n</hash>\n"
1.9.3p392 :002 > {status: 500, error: "herro shraggy!"}.to_json
=> "{\"status\":500,\"error\":\"herro shraggy!\"}"
在中间件中,您将X-Cascade
在代码中以及与 Rails 在 Rack 中的异常处理相关的各个地方看到标头。根据这个答案,X-Cascade
标头设置为pass
告诉 Rack 尝试其他路由来查找资源。
Rails 3.2.x:可以处理机架中的异常
在 Rails 3.2.x 中,to_(format)
为响应正文等执行的代码不在public_exceptions.rb中。它只处理html格式。
也许您可以尝试通过补丁将旧的中间件替换为较新的版本。
如果您希望 Rack 在没有补丁的情况下以更具体的方式处理您的错误,请参阅 José Valim 的文章中的 #3,“ Rails 3.2 中我最喜欢的五个“隐藏”功能”。
在那个和另一个答案中也提到,你可以使用config.exceptions_app = self.routes
. 然后使用指向自定义控制器的路由,您可以像处理任何其他请求一样处理来自任何控制器的错误。请注意config.consider_all_requests_local = false
您的config/environments/development.rb
.
您不必使用路线来使用exceptions_app
. 虽然它可能有点吓人,但它只是一个 proc/lambda,它接受一个哈希并返回一个格式为: 的数组[http_status_code_number, {headers hash...}, ['the response body']]
。例如,您应该能够在 Rails 3.2.x 配置中执行此操作,以使其处理 Rails 4.0 之类的错误(这是最新的 public_exceptions 中间件折叠):
config.exceptions_app = lambda do |env|
exception = env["action_dispatch.exception"]
status = env["PATH_INFO"][1..-1]
request = ActionDispatch::Request.new(env)
content_type = request.formats.first
body = { :status => status, :error => exception.message }
format = content_type && "to_#{content_type.to_sym}"
if format && body.respond_to?(format)
formatted_body = body.public_send(format)
[status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}",
'Content-Length' => body.bytesize.to_s}, [formatted_body]]
else
found = false
path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path))
if found || File.exist?(path)
[status, {'Content-Type' => "text/html; charset=#{ActionDispatch::Response.default_charset}",
'Content-Length' => body.bytesize.to_s}, [File.read(path)]]
else
[404, { "X-Cascade" => "pass" }, []]
end
end
end
注意:对于该处理的任何问题,故障安全实现在ActionDispatch::ShowExceptions
这里。
Rails 3 和 4:在 Rails 控制器中处理一些异常
如果您希望在控制器本身中有错误呈现,您可以执行以下操作:
def show
respond_with @bar = Bar.where(:foo_id => params[:id].to_s).first!
rescue ActiveRecord::RecordNotFound => e
respond_to do |format|
format.json => { :error => e.message }, :status => 404
end
end
但是,您不需要引发错误。你也可以这样做:
def show
@bar = Bar.where(:foo_id => params[:id].to_s).first
if @bar
respond_with @bar
else
respond_to do |format|
format.json => { :error => "Couldn't find Bar with id=#{params[:id]}" }, :status => 404
end
end
end
您还可以使用rescue_from,例如在您的控制器或 ApplicationController 等中:
rescue_from ActiveRecord::RecordNotFound, with: :not_found
def not_found(exception)
respond_to do |format|
format.json => { :error => e.message }, :status => 404
end
end
或者:
rescue_from ActiveRecord::RecordNotFound do |exception|
respond_to do |format|
format.json => { :error => e.message }, :status => 404
end
end
虽然一些常见的错误可以在控制器中处理,但如果您的错误与缺少路由等相关的错误以 json 等格式格式化,则需要在 Rack 中间件中处理。