在 Rails 中使用 Postgres UUID 时避免 PG::InvalidTextRepresentation 错误 [英] Avoid PG::InvalidTextRepresentation error when using Postgres UUID in Rails

查看:66
本文介绍了在 Rails 中使用 Postgres UUID 时避免 PG::InvalidTextRepresentation 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始对我所有模型的 id 字段使用 Postgres UUID 类型.效果很好,并且(大部分)在 Rails 4 中得到支持:

I started using Postgres UUID type for all my models' id fields. Works great and is supported (for the most part) in Rails 4:

create_table :users, id: :uuid do |t|
  # ...
end

问题在于,如果您尝试查找 id 为 X 的行,但 X 不是格式正确的 UUID 字符串,则 Postgres 将引发错误.

The problem is that Postgres will raise an error if you attempt to find a row where id is X, but X is not a properly formatted UUID string.

> 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.或者他们可能会获得指向不存在的对象的链接不再存在.

So if my user is on a page where a UUID is in the URL, and they then try to change the UUID, they'll get a 500 error instead of 404. Or perhaps they get a link to an object that no longer exists.

我怎样才能以一种干燥的方式避免这种情况?我不能只是拯救 PG::InvalidTextRepresentation 并渲染 404 因为 其他事情 也可能导致此错误.

How can I go about avoiding this scenario in a DRY way? I can't just rescue the PG::InvalidTextRepresentation and render 404 because other things can cause this error as well.

更新

我认为关于 ID 参数格式的正则表达式是干净的,如果不匹配,它会引发 404:

I think that a regex on the format of the ID param is clean, and it raises a 404 if it doesn't match:

resources :users, id: /uuid-regex-here/

但我仍然有保持干燥的问题;我不想把它放在我的路线中的每一个资源上.我可以在一个语句中声明多个资源,但前提是没有其他选项(如成员操作).所以也许更好的问题是:有没有办法为所有路由设置 id 正则表达式?

But I still have the problem of staying DRY; I don't want to put this on every single resource in my routes. I can declare multiple resources in one statement, but only if don't other options to it like member actions. So perhaps a better question is: Is there a way to set the id regex for all routes?

推荐答案

您可以通过 constraints() do ... end 一次向多条路由添加路由约束.

You can add a routing constraint to multiple routes at a time via constraints() do ... end.

我最终这样做并在所有 :id 参数上设置了全局约束以将其与 UUID 正则表达式匹配:

I ended up doing this and setting a global constraint on all :id params to match it to a UUID regexp:

MyApp::Application.routes.draw do
  constraints(id: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i) do

    # my routes here

  end
end

这样,/posts/123 或/posts/foobar 在调用控制器动作之前不再匹配/posts/:id 和 404,从而避免 PG 类型错误.

This way, /posts/123 or /posts/foobar no longer match /posts/:id and 404 before ever invoking the controller action, thus avoiding the PG type error.

我所有的模型都将使用 UUID 作为它们的 ID,所以这是干净和干燥的.如果我也有一些带有整数 ID 的模型,它会不那么干净.

All of my models will use UUID for their IDs so this is clean and DRY. If I had some models with integer IDs as well, it'd be a little less clean.

这篇关于在 Rails 中使用 Postgres UUID 时避免 PG::InvalidTextRepresentation 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆