对于我的项目,我需要有自定义网址,这不应该很容易猜到,因为它会增加对象的整数ID。为了解决这个问题,我为我的对象提供了一个unique_id属性,该属性是一个字符串,并编写了由resources :objects
自己生成的七个动作,如下所示:
get '/objects' => 'objects#index', as: :objects
post '/objects' => 'objects#create'
get '/objects/new' => 'objects#new', as: :new_object
get '/:unique_id/edit' => 'objects#edit', as: :edit_object
get '/:unique_id' => 'objects#show', as: :object
put '/:unique_id' => 'objects#update'
delete '/:unique_id' => 'objects#destroy'
一切都很好,我只需告诉控制器通过Object.find_by_unique_id(params[:unique_id])
而不是Object.find(params[:id])
找到对象
我可以创建,阅读和删除完美,但我无法更新。
当我打开edit_object_path时,它会正确呈现表单,但是当我点击“更新对象”时,它就会搞砸了。
从WEBrick输出我可以看到它创建了一个PUT请求,但它请求对象的id而不是unique_id。例如,不是请求PUT /osefushe7398hr9
,而是PUT /26
。甚至没有调用update方法,而是要求创建一个unique_id为26的新对象。
我真的不知道在哪里更改该行为或如何传递unique_id而不是id。
答案 0 :(得分:3)
Rails模型有一个您可能想要覆盖的方法来实现此目的,称为to_param
方法。此方法的默认行为是返回模型实例的ID(我相信您正在尝试更改)。
根据您当前的布局,我会抛弃您所有的路线更改。在模型中,添加:
def to_param
"#{unique_id.parameterize}"
end
现在,通过正常路由,/ objects /:变量的请求将按您的意愿运行。
使用参数化方法,您可以安全地不遇到不友好的URL。
覆盖to_param方法的一个小缺点是,现在在控制器中使用Model.find方法的其他操作(:edit,:update和:destroy)都需要更改为Model.find_by_unique_id [if你保持RESTful]。
答案 1 :(得分:1)
在表单中,您可以明确地告诉它要发布到哪个URL以及与其一起使用的参数。例如(使用HAML和form_tag)
= form_tag object_path(@object.unique_id), :method => :put do
您还可以更明确地使用:
= form_tag object_path(:id => @object.unique_id), :method => :put do
答案 2 :(得分:0)
好的解决方案是添加
def to_param
unique_id
end
到没有参数化的对象模型或#{}语法。 我实际上发现事故是试图将unique_id传递给第二个解决方案中提到的表单。事实证明,我没有像解决方案二中建议的那样更改form_for标记。参数化是将unique_id设为小写的原因。
现在一切都按预期工作(并且仍然很安静)