10

我开始为我所有模型的id字段使用Postgres UUID类型。在轨道4的伟大工程,支持(大部分):在Rails中使用Postgres UUID时避免PG :: InvalidTextRepresentation错误

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

的问题是,如果你试图找到一排,其中ID为X Postgres将产生一个错误,但X不是格式正确的UUID字符串。

> 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 

所以,如果我的用户是一个页面上,其中一个UUID是在URL,然后他们试图改变UUID,他们会得到的,而不是404 500错误或者也许他们得到一个链接一个不再存在的对象。

我怎样才能避免这种情况下干的方式?我不能挽救并渲染404,因为other things也会导致此错误。

UPDATE

我认为,在ID参数的时格式的正则表达式是干净的,而且它提出了一个404,如果不匹配:

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

但我仍然有停留干的问题;我不想把这个放在我的路线中的每一个资源上。我可以在一个语句中声明多个资源,但前提是不要将其他选项用作成员操作。 所以也许更好的问题是:有没有一种方法来设置所有路线的ID正则表达式?

+0

你为什么要通过foobar?你的路线在它落在你的模型之前是否应该抓住它? –

+0

@Denis我想我可以对id参数进行约束,以确保它匹配UUID正则表达式。但是我必须为我的路线中的每一个资源都做到这一点......或者您还有其他想法吗? – tybro0103

+0

也许你的控制器的'before_filter'可以工作。 –

回答

7

您可以通过constraints() do ... end一次将路由约束添加到多个路由。

我终于实现了这一点,并设置所有:id PARAMS一个全球性的约束匹配到一个UUID正则表达式:

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 

这样,/职位/ 123或/职位/ foobar的不再匹配/职位/:id和404之前调用控制器操作,从而避免PG类型的错误。

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

+0

如果你使用的是UUID gem,你可以使用他们的validate方法而不是自己滚动https://github.com/assaf/uuid/blob/master/lib/uuid.rb#L199 –

+0

@BrianHahn很高兴知道,尽管我并没有真的在滚动我的自己......这只是一个正则表达式。 – tybro0103

+0

我的意思是它会在已经拥有UUID gem的环境中滚动自己。当UUID gem不是项目中的依赖项时,您的正则表达式看起来很好! –

2

如果你不想限制添加到所有路线追赶无效的UUID,那么你可以在一个before_filter杂牌,这样的事情:

before_filter do 
    if(params.has_key?(:id)) 
    uuid = params[:id].strip.downcase.gsub('-', '').gsub(/\A\{?(\h{32})\}?\z/, '\1') 
    raise ActiveRecord::RecordNotFound if(uuid.blank?) 
    end 
end 

注意,UUID可有各种形式(请参阅the fine manual),因此最好在验证它们之前对它们进行规范化,或者同时进行规范化和验证。

你可以将它放入你的ApplicationController如果你知道你的所有:id参数应该是的UUID或把逻辑在需要它的控制器的ApplicationController方法和before_filter :make_sure_id_is_a_uuid

+0

这并不坏,如果我没有找到一种方法将正则表达式添加到路由中,我将最终与此相关 – tybro0103

+0

另一个猴子修补的可能性是AR PostgreSQL驱动里面的类型转换的东西,在那里有一个很大的'case'语句 –