【发布时间】:2014-02-15 19:31:00
【问题描述】:
我开始对所有模型的 id 字段使用 Postgres UUID 类型。效果很好并且在 Rails 4 中得到支持(大部分):
create_table :users, id: :uuid do |t|
# ...
end
问题在于,如果您尝试查找 id 为 X 的行,但 X 不是格式正确的 UUID 字符串,Postgres 将引发错误。
> User.find "3ac093e2-3a5e-4744-b49f-117b032adc6c"
ActiveRecord::RecordNotFound # good, will cause a 404
> User.find "foobar"
PG::InvalidTextRepresentation: ERROR # bad, will cause a 500
因此,如果我的用户在 URL 中包含 UUID 的页面上,然后他们尝试更改 UUID,他们将收到 500 错误而不是 404。或者他们可能会获得指向不存在的对象的链接不再存在。
我怎样才能以 DRY 的方式避免这种情况?我不能只拯救PG::InvalidTextRepresentation 并渲染404,因为other things 也会导致此错误。
更新
我认为 ID 参数格式的正则表达式是干净的,如果不匹配,它会引发 404:
resources :users, id: /uuid-regex-here/
但我仍然有保持干燥的问题;我不想把它放在我路线中的每一个资源上。我可以在一个语句中声明多个资源,但前提是它的其他选项不像成员操作。 所以也许一个更好的问题是:有没有办法为所有路由设置 id 正则表达式?
【问题讨论】:
-
你为什么要通过 foobar?你的路线难道不应该在它到达你的模型之前就捕捉到它吗?
-
@Denis 我想我可以对 id 参数施加约束,确保它与 UUID 正则表达式匹配。但是我必须对路线中的每一个资源都这样做......还是你有其他想法?
-
也许你的控制器的
before_filter会起作用。 -
@tybro0103: 就我个人而言,如果我忘记让自己的路由验证 id 的格式是否正确,或者某个随机调用发送的 id 格式错误,我实际上会要他们咳一个错误。我对 Rails 不够熟悉,无法准确说明如何大规模自动验证它们,但我猜 mu 对他的建议有所了解。
-
@Denis:潜在的问题是 Rails 的人懒得把验证放在正确的地方,他们假设
Model.find如果没有找到任何记录,就会引发 RecordNotFound原因(当 PK 为整数时,包括类型错误,例如M.find('pancakes'))。在 Rails 模型中,为路线添加约束可能是正确的做法,过滤器是一种快速破解。 Rails 充斥着未说明的假设(尝试添加包含电子邮件地址的路由,看看会发生什么),当您偏离常规路径时,它会横向移动。
标签: ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord rails-postgresql