在浏览器中渲染模板并更改url字符串?

我有2个动作 – 编辑和更新。 “编辑”中的表单将值提交给“更新”操作。 当保存模型失败时,我渲染编辑teplate,用户看到错误,并且字段预先填充了之前填充的内容。 有一个巨大但对我来说 – 在用户浏览器中的URL面板中有/ user / update,即使(因为)我渲染了编辑模板。 我可以通过在更新操作中将一些参数传递给render方法来改变它吗? 我不希望用户看到除了编辑之外还有任何(更新)操作。 可能吗?

有两种方法:

1)从更新操作重定向回编辑操作,而不是仅渲染模板,并传递要用于填充正在编辑的对象的错误消息和属性。 这将导致URL为/ user / edit。

 def更新
   @user = User.find(params [:id])
   if @ user.update_attributes params [:user]
     ...
  其他
     redirect_to edit_user_path(@ user,:messages => @ user.errors)
  结束
结束

2)发布到编辑操作而不是更新操作,并完全删除更新操作。 你可以使用request.post吗? 在您的编辑操作中检查请求是发布请求还是获取请求,然后使用相同的函数定义执行更新和编辑操作。

 def编辑
   @user = User.find(params [:id])
  如果request.post?
     @ user.update_attributes params [:user]
     ...
  其他
     ...
  结束
结束

注意:请记住,您无法真正隐藏客户端的POST操作,因为他们始终可以查看您的源代码并查看您在表单中发布的操作。

以下是第三种方法:

在您的routes.rb中

 resources :users match 'users/:id/edit' => 'users#update', :via => :put, :as => :put_user 

在您的视图中(例如edit.html.erb)

 <%= form_for @user, :url => put_user_path do |f| %> ... <% end %> 

在您的控制器中(例如users_controller.rb)

 def update @user = User.find(params[:id]) if @user.update_attributes(params[:user]) ... else render 'edit' end end 

我会说你很简单没有理解为什么REST在Rails中的工作原理,更重要的是你应该尝试在构建自己的想法之前学习框架。

首先,在idomatic rails路线中没有动作。 您通过向things/:id发送PATCH或PUT请求来执行更新。 例外是newedit因为这些操作用于呈现表单。

  Prefix Verb URI Pattern Controller#Action things GET /things(.:format) things#index POST /things(.:format) things#create new_thing GET /things/new(.:format) things#new edit_thing GET /things/:id/edit(.:format) things#edit thing GET /things/:id(.:format) things#show PATCH /things/:id(.:format) things#update PUT /things/:id(.:format) things#update DELETE /things/:id(.:format) things#destroy 

编辑操作(GET / things /:id / edit)显示用于编辑资源的表单。 这是一个幂等行为,因为它应该返回相同的结果并且不会改变资源。

更新操作(PATCH | PUT / things /:id)呈现对资源执行非幂等变换的结果。

您还应该注意,Rails中的呈现与重定向无关。 这是一种常见的误解。

 render :edit 

实际上只是简写:

 render "things/edit" 

它不会调用编辑操作 – 两者只是共享视图,但在概念上是完全不同的操作。

重新加载该页面当然不会显示与/things/1的GET请求相同的结果 – 而不是PATCH / PUT。 请记住,GET请求应始终是幂等的。

重定向将在历史记录中创建一个条目,因为它是一个单独的GET请求以及您需要将整个表单主体作为GET参数传递这一事实并不理想。 而且你基本上都在抛弃铁轨的真正力量,这是你从拥抱它的惯例中获得的生产力。

一个稍微更现代的版本基于CL Chang的答案

 resources :jobs, except: [:update] do member do patch 'edit', action: :update, :as => :update_edit end end 

这会生成所有标准的restful路由,标准更新路由除外。 (如果您不想要所有操作,那么您只能使用only: []

另外,它产生了

 update_edit_job PATCH /jobs/:id/edit(.:format) 

现在您只需更新表单以指定路径

 <%= form_for @job, :url => update_edit_job_path do |f| %> ... <% end %> 

因此,它不是通过补丁发送到/更新,而是通过补丁转到/ jobs //编辑,这将触及您的更新操作

现在,如果出现错误,您可以渲染编辑,并且所有错误都将可见 – 但用户不会注意到该url与编辑错误不同(因为只有方法不同)

 def update @job = Job.find(params[:id]) if @job.update_attributes(user_params) #redirect somewhere??? else render 'edit' end end 

可以使用此处描述的pushState()方法: https : //developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState ()_method

例如,您可以将其放在javascript函数中,该函数在发生validation错误时调用:

  var url = document.referrer; window.history.pushState(null, null, url);