我的 Rails 应用程序 Controller 中有以下代码:
def delete
object = model.datamapper_class.first(:sourced_id => params[:sourced_id])
if object.blank?
render :xml => "No #{resource} with sourced_id #{params[:sourced_id]}", :status => :not_found and return
end
object.destroy
render :xml => "", :status => :no_content
rescue MysqlError => e
puts "raised MysqlError #{e.message}"
render :xml => e.message, :status => :unprocessable_entity and return
rescue Mysql::Error => e
puts "raised Mysql::Error #{e.message}"
render :xml => e.message, :status => :unprocessable_entity and return
rescue Exception => e
puts "not a MysqlError, instead it was a #{e.class.name}"
render :xml => e.message, :status => :unprocessable_entity and return
end
当我运行规范以确保外键约束有效时,我得到以下信息:
not a MysqlError, instead it was a MysqlError
这里可能发生了什么?
一些祖先信息:当我改变救援方式时给我这个:
puts MysqlError.ancestors
puts "****"
puts Mysql::Error.ancestors
puts "****"
puts e.class.ancestors
这就是我得到的:
Mysql::Error
StandardError
Exception
ActiveSupport::Dependencies::Blamable ...
****
Mysql::Error
StandardError
Exception
ActiveSupport::Dependencies::Blamable ...
****
MysqlError
StandardError
Exception
ActiveSupport::Dependencies::Blamable ...
全局命名空间中是否存在别名导致 MysqlError 类无法访问?
最佳答案
Ruby 类只是对象,因此比较基于对象标识(即底层的相同指针)。
不确定您的情况发生了什么,但我会尝试在几个位置进行调试,并查看您为 MysqlError 获得的对象 ID 和祖先。我怀疑不同的模块中有两个这样的对象,并且您的 catch 子句引用了错误的对象。
编辑:
这很奇怪。我现在的猜测是,MysqlError 或其祖先之一已包含在 Controller 自己的类链上的两个不同点上,这在某种程度上导致了异常捕获。
理论 #2 是,由于 Rails 重新定义了 const_missing 来执行自动要求,因此您希望在异常处理子句中获得 UndefinedConstant 异常,而不是在源代码树中找到具有该名称的内容,天知道在哪里。您应该能够通过关闭自动要求进行测试来查看是否是这种情况(即在开发和生产模式下进行一些调试)。
有一种语法可以强制您的引用从根开始,如果您能找出要引用的正确语法,这可能会有所帮助:
::Foo::Bar
咆哮:
这种事情是我认为 ruby 的一些缺陷表现出来的地方。在底层,Ruby 的对象模型和作用域是所有相互指向的对象结构,其方式与 javascript 或其他基于原型(prototype)的语言非常相似。但这在您在该语言中使用的类/模块语法中表现得不一致。似乎通过一些仔细的重构,您可以使这些东西变得更清晰并简化语言,尽管这当然与现有代码高度不兼容。
提示:
当使用 put 进行调试时,请尝试执行 put foo.inspect,因为这将以您习惯的 irb 方式显示它。
关于ruby - 什么时候 Ruby 类不是那个 Ruby 类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1134752/