Rails 3: Custom Restful Routes: Change Edit-Action behavior



对于我的项目,我需要有自定义的url,因为随着对象的整数id的增加,这些url应该不容易猜测。为了解决这个问题,我给我的对象一个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。

Rails模型有一个方法,您可能想要覆盖它来实现这一点,称为to_param方法。此方法的默认行为是返回模型实例的ID(我认为您正试图更改该ID)。

按照你目前的布局,我会放弃你所有的路线变更。在模型中,添加:

def to_param
  "#{unique_id.parameterize}"
end

因此,现在,使用普通路由,/objects/:变量的请求将按照您的意愿进行操作。

使用参数化方法,您可以安全地避免遇到不友好的URL。

覆盖to_param方法的一个小缺点是,现在控制器中使用Model.find方法的其他操作(:edit、:update和:destroy)都需要更改为Model.find_by_unique_id[如果您保持RESTful]。

在表单中,您可以明确地告诉它要发布到哪个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

好的,解决方案是添加

def to_param
  unique_id
end

到对象模型,而不使用参数化或#{}语法。事实上,我在尝试将unique_id传递到第二个解决方案中提到的表单时意外发现了这一点。事实证明,我不必像解决方案2中建议的那样更改form_for标记。parameterize是unique_id变为小写的原因。

现在一切都按预期工作(并且仍然是静止的)

最新更新